Skip to content

Commit fe9140f

Browse files
authored
[gw api] Add TCP_UDP for gateway api (#4469)
* tcp_udp support in gateway api * documentation for tcp_udp * e2e test for tcp_udp
1 parent bb18bb2 commit fe9140f

18 files changed

+662
-286
lines changed

apis/gateway/v1beta1/loadbalancerconfig_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ type WAFv2Configuration struct {
152152
ACL string `json:"webACL"`
153153
}
154154

155-
// +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})?$"
155+
// +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})?$"
156156
type ProtocolPort string
157157
type ListenerConfiguration struct {
158158
// protocolPort is identifier for the listener on load balancer. It should be of the form PROTOCOL:PORT

config/crd/gateway/gateway-crds.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ spec:
561561
protocolPort:
562562
description: protocolPort is identifier for the listener on
563563
load balancer. It should be of the form PROTOCOL:PORT
564-
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})?$
564+
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})?$
565565
type: string
566566
sslPolicy:
567567
description: sslPolicy is the security policy that defines which

config/crd/gateway/gateway.k8s.aws_loadbalancerconfigurations.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ spec:
167167
protocolPort:
168168
description: protocolPort is identifier for the listener on
169169
load balancer. It should be of the form PROTOCOL:PORT
170-
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})?$
170+
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})?$
171171
type: string
172172
sslPolicy:
173173
description: sslPolicy is the security policy that defines which

controllers/gateway/targetgroup_configuration_controller.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"github.com/go-logr/logr"
7+
corev1 "k8s.io/api/core/v1"
78
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
89
"k8s.io/apimachinery/pkg/types"
910
"k8s.io/client-go/kubernetes"
@@ -115,11 +116,25 @@ func (r *targetgroupConfigurationReconciler) handleDelete(tgConf *elbv2gw.Target
115116
Name: tgConf.Spec.TargetReference.Name,
116117
}
117118

118-
eligibleForRemoval := r.serviceReferenceCounter.IsEligibleForRemoval(svcReference, allGateways)
119+
svc := &corev1.Service{}
120+
err := r.k8sClient.Get(context.Background(), svcReference, svc)
119121

120-
// if the targetgroup configuration is still in use, we should not delete it
121-
if !eligibleForRemoval {
122-
return fmt.Errorf("targetgroup configuration [%+v] is still in use", k8s.NamespacedName(tgConf))
122+
referenceCheckNeeded := true
123+
if err != nil {
124+
notFoundErr := client.IgnoreNotFound(err)
125+
if notFoundErr != nil {
126+
return notFoundErr
127+
}
128+
referenceCheckNeeded = false
129+
}
130+
131+
if referenceCheckNeeded {
132+
eligibleForRemoval := r.serviceReferenceCounter.IsEligibleForRemoval(svcReference, allGateways)
133+
134+
// if the targetgroup configuration is still in use, we should not delete it
135+
if !eligibleForRemoval {
136+
return fmt.Errorf("targetgroup configuration [%+v] is still in use", k8s.NamespacedName(tgConf))
137+
}
123138
}
124139
return r.finalizerManager.RemoveFinalizers(context.Background(), tgConf, shared_constants.TargetGroupConfigurationFinalizer)
125140
}

docs/guide/gateway/l4gateway.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,95 @@ spec:
8585
* **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`.
8686
* **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.
8787

88+
89+
### Combined Protocols
90+
AWS NLB supports combining TCP and UDP on the same listener; the protocol is called TCP_UDP. This powerful
91+
paradigm allows the load balancer to serve different protocols for different applications on the same listener port.
92+
The LBC implements this protocol merging capability.
93+
94+
#### Combined protocol quirks
95+
96+
AWS NLB assumes that in a combined protocol set up,
97+
all targets are able to serve both protocols. To prevent configuration duplication, we follow this same pattern for constructing
98+
the combined protocol listener. TCP_UDP listeners are able to attach routes of type TCP and UDP, each route attached
99+
generates a TCP_UDP target group.
100+
101+
102+
#### Combined protocol examples
103+
104+
```yaml
105+
apiVersion: gateway.networking.k8s.io/v1
106+
kind: Gateway
107+
metadata:
108+
name: my-tcp-udp-gateway
109+
namespace: tcp-udp
110+
spec:
111+
gatewayClassName: aws-nlb-gateway-class
112+
listeners:
113+
- allowedRoutes:
114+
namespaces:
115+
from: Same
116+
name: tcp-app
117+
port: 80
118+
protocol: TCP
119+
- allowedRoutes:
120+
namespaces:
121+
from: Same
122+
name: udp-app
123+
port: 80
124+
protocol: UDP
125+
---
126+
apiVersion: gateway.networking.k8s.io/v1alpha2
127+
kind: UDPRoute
128+
metadata:
129+
name: my-udp-app-route
130+
namespace: tcp-udp
131+
spec:
132+
parentRefs:
133+
- group: gateway.networking.k8s.io
134+
kind: Gateway
135+
name: my-tcp-udp-gateway
136+
sectionName: udp-app
137+
rules:
138+
- backendRefs:
139+
- group: ""
140+
kind: Service
141+
name: udpechoserver
142+
port: 8080
143+
weight: 1
144+
```
145+
146+
To customize the target group created, it's no different from a single protocol
147+
```yaml
148+
apiVersion: gateway.k8s.aws/v1beta1
149+
kind: TargetGroupConfiguration
150+
metadata:
151+
name: example-tg-config
152+
namespace: tcp-udp
153+
spec:
154+
defaultConfiguration:
155+
targetType: ip
156+
targetReference:
157+
group: ""
158+
kind: Service
159+
name: udpechoserver
160+
```
161+
162+
To customize the listener:
163+
```yaml
164+
apiVersion: gateway.k8s.aws/v1beta1
165+
kind: LoadBalancerConfiguration
166+
metadata:
167+
name: nlb-lb-config
168+
namespace: tcp-udp
169+
spec:
170+
listenerConfigurations:
171+
- protocolPort: TCP_UDP:80
172+
listenerAttributes:
173+
- key: tcp.idle_timeout.seconds
174+
value: "60"
175+
```
176+
88177
### L4 Gateway API Limitations for NLBs
89178
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.
90179

helm/aws-load-balancer-controller/crds/gateway-crds.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ spec:
561561
protocolPort:
562562
description: protocolPort is identifier for the listener on
563563
load balancer. It should be of the form PROTOCOL:PORT
564-
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})?$
564+
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})?$
565565
type: string
566566
sslPolicy:
567567
description: sslPolicy is the security policy that defines which

pkg/deploy/elbv2/listener_manager.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,12 @@ var alpnNone = []string{
3131
}
3232

3333
var PROTOCOLS_SUPPORTING_LISTENER_ATTRIBUTES = map[elbv2model.Protocol]bool{
34-
elbv2model.ProtocolHTTP: true,
35-
elbv2model.ProtocolHTTPS: true,
36-
elbv2model.ProtocolTCP: true,
37-
elbv2model.ProtocolUDP: false,
38-
elbv2model.ProtocolTLS: false,
34+
elbv2model.ProtocolHTTP: true,
35+
elbv2model.ProtocolHTTPS: true,
36+
elbv2model.ProtocolTCP: true,
37+
elbv2model.ProtocolUDP: false,
38+
elbv2model.ProtocolTLS: false,
39+
elbv2model.ProtocolTCP_UDP: true,
3940
}
4041

4142
// ListenerManager is responsible for create/update/delete Listener resources.

pkg/gateway/model/mock_tg_builder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func (m *mockTargetGroupBuilder) getLocalFrontendNlbData() map[string]*elbv2mode
2020
}
2121

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

2626
if len(m.tgs) > 0 {

pkg/gateway/model/model_build_listener.go

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (l listenerBuilderImpl) buildListeners(ctx context.Context, stack core.Stac
5858
portsWithRoutes := sets.Int32KeySet(routes)
5959
// Materialise the listener only if listener has associated routes
6060
if len(gwLsPorts.Intersection(portsWithRoutes).List()) != 0 {
61-
lbLsCfgs := mapLoadBalancerListenerConfigsByPort(lbCfg, gw.Spec.Listeners)
61+
lbLsCfgs := mapLoadBalancerListenerConfigsByPort(lbCfg, gwLsCfgs)
6262
for _, port := range gwLsPorts.Intersection(portsWithRoutes).List() {
6363
ls, err := l.buildListener(ctx, stack, lb, gw, port, routes[port], lbCfg, gwLsCfgs[port], lbLsCfgs[port])
6464
if err != nil {
@@ -83,7 +83,7 @@ func (l listenerBuilderImpl) buildListeners(ctx context.Context, stack core.Stac
8383
return secrets, nil
8484
}
8585

86-
func (l listenerBuilderImpl) buildListener(ctx context.Context, stack core.Stack, lb *elbv2model.LoadBalancer, gw *gwv1.Gateway, port int32, routes []routeutils.RouteDescriptor, lbCfg elbv2gw.LoadBalancerConfiguration, gwLsCfg *gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) (*elbv2model.Listener, error) {
86+
func (l listenerBuilderImpl) buildListener(ctx context.Context, stack core.Stack, lb *elbv2model.LoadBalancer, gw *gwv1.Gateway, port int32, routes []routeutils.RouteDescriptor, lbCfg elbv2gw.LoadBalancerConfiguration, gwLsCfg gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) (*elbv2model.Listener, error) {
8787
var listenerSpec *elbv2model.ListenerSpec
8888

8989
var err error
@@ -104,7 +104,7 @@ func (l listenerBuilderImpl) buildListener(ctx context.Context, stack core.Stack
104104
return elbv2model.NewListener(stack, lsResID, *listenerSpec), nil
105105
}
106106

107-
func (l listenerBuilderImpl) buildListenerSpec(ctx context.Context, lb *elbv2model.LoadBalancer, gw *gwv1.Gateway, port int32, lbCfg elbv2gw.LoadBalancerConfiguration, gwLsCfg *gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) (*elbv2model.ListenerSpec, error) {
107+
func (l listenerBuilderImpl) buildListenerSpec(ctx context.Context, lb *elbv2model.LoadBalancer, gw *gwv1.Gateway, port int32, lbCfg elbv2gw.LoadBalancerConfiguration, gwLsCfg gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) (*elbv2model.ListenerSpec, error) {
108108
tags, err := l.buildListenerTags(lbCfg)
109109
if err != nil {
110110
return &elbv2model.ListenerSpec{}, err
@@ -133,7 +133,7 @@ func (l listenerBuilderImpl) buildListenerSpec(ctx context.Context, lb *elbv2mod
133133
return listenerSpec, nil
134134
}
135135

136-
func (l listenerBuilderImpl) buildL7ListenerSpec(ctx context.Context, lb *elbv2model.LoadBalancer, gw *gwv1.Gateway, lbCfg elbv2gw.LoadBalancerConfiguration, port int32, gwLsCfg *gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) (*elbv2model.ListenerSpec, error) {
136+
func (l listenerBuilderImpl) buildL7ListenerSpec(ctx context.Context, lb *elbv2model.LoadBalancer, gw *gwv1.Gateway, lbCfg elbv2gw.LoadBalancerConfiguration, port int32, gwLsCfg gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) (*elbv2model.ListenerSpec, error) {
137137
listenerSpec, err := l.buildListenerSpec(ctx, lb, gw, port, lbCfg, gwLsCfg, lbLsCfg)
138138
if err != nil {
139139
return &elbv2model.ListenerSpec{}, err
@@ -147,7 +147,7 @@ func (l listenerBuilderImpl) buildL7ListenerSpec(ctx context.Context, lb *elbv2m
147147
return listenerSpec, nil
148148
}
149149

150-
func (l listenerBuilderImpl) buildL4ListenerSpec(ctx context.Context, stack core.Stack, lb *elbv2model.LoadBalancer, gw *gwv1.Gateway, lbCfg elbv2gw.LoadBalancerConfiguration, port int32, routes []routeutils.RouteDescriptor, gwLsCfg *gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) (*elbv2model.ListenerSpec, error) {
150+
func (l listenerBuilderImpl) buildL4ListenerSpec(ctx context.Context, stack core.Stack, lb *elbv2model.LoadBalancer, gw *gwv1.Gateway, lbCfg elbv2gw.LoadBalancerConfiguration, port int32, routes []routeutils.RouteDescriptor, gwLsCfg gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) (*elbv2model.ListenerSpec, error) {
151151
listenerSpec, err := l.buildListenerSpec(ctx, lb, gw, port, lbCfg, gwLsCfg, lbLsCfg)
152152
if err != nil {
153153
return &elbv2model.ListenerSpec{}, err
@@ -177,7 +177,7 @@ func (l listenerBuilderImpl) buildL4ListenerSpec(ctx context.Context, stack core
177177
return nil, nil
178178
}
179179

180-
arn, tgErr := l.tgBuilder.buildTargetGroup(stack, gw, port, lb.Spec.IPAddressType, routeDescriptor, backend)
180+
arn, tgErr := l.tgBuilder.buildTargetGroup(stack, gw, port, listenerSpec.Protocol, lb.Spec.IPAddressType, routeDescriptor, backend)
181181
if tgErr != nil {
182182
return &elbv2model.ListenerSpec{}, tgErr
183183
}
@@ -222,7 +222,7 @@ func (l listenerBuilderImpl) buildListenerRules(ctx context.Context, stack core.
222222
}
223223
targetGroupTuples := make([]elbv2model.TargetGroupTuple, 0, len(rule.GetBackends()))
224224
for _, backend := range rule.GetBackends() {
225-
arn, tgErr := l.tgBuilder.buildTargetGroup(stack, gw, port, ipAddressType, route, backend)
225+
arn, tgErr := l.tgBuilder.buildTargetGroup(stack, gw, port, ls.Spec.Protocol, ipAddressType, route, backend)
226226
if tgErr != nil {
227227
return nil, tgErr
228228
}
@@ -313,7 +313,7 @@ func buildListenerAttributes(lsCfg *elbv2gw.ListenerConfiguration) ([]elbv2model
313313
return attributes, nil
314314
}
315315

316-
func (l listenerBuilderImpl) buildCertificates(ctx context.Context, gw *gwv1.Gateway, port int32, gwLsCfg *gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) ([]elbv2model.Certificate, error) {
316+
func (l listenerBuilderImpl) buildCertificates(ctx context.Context, gw *gwv1.Gateway, port int32, gwLsCfg gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) ([]elbv2model.Certificate, error) {
317317
if !isSecureProtocol(gwLsCfg.protocol) {
318318
return []elbv2model.Certificate{}, nil
319319
}
@@ -408,7 +408,7 @@ func buildL4ListenerDefaultActions(arn core.StringToken) []elbv2model.Action {
408408
}
409409
}
410410

411-
func (l listenerBuilderImpl) buildMutualAuthenticationAttributes(ctx context.Context, gwLsCfg *gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) (*elbv2model.MutualAuthenticationAttributes, error) {
411+
func (l listenerBuilderImpl) buildMutualAuthenticationAttributes(ctx context.Context, gwLsCfg gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) (*elbv2model.MutualAuthenticationAttributes, error) {
412412
// Skip mTLS configuration for non-secure protocols
413413
if !isSecureProtocol(gwLsCfg.protocol) || lbLsCfg == nil || lbLsCfg.MutualAuthentication == nil {
414414
return nil, nil
@@ -453,7 +453,7 @@ func (l listenerBuilderImpl) buildMutualAuthenticationAttributes(ctx context.Con
453453
}, nil
454454
}
455455

456-
func (l listenerBuilderImpl) buildSSLPolicy(gwLsCfg *gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) (*string, error) {
456+
func (l listenerBuilderImpl) buildSSLPolicy(gwLsCfg gwListenerConfig, lbLsCfg *elbv2gw.ListenerConfiguration) (*string, error) {
457457
if !isSecureProtocol(gwLsCfg.protocol) {
458458
return nil, nil
459459
}
@@ -488,17 +488,34 @@ func buildListenerALPNPolicy(listenerProtocol elbv2model.Protocol, lbLsCfg *elbv
488488
}
489489

490490
// mapGatewayListenerConfigsByPort creates a mapping of ports to listener configurations from the Gateway listeners.
491-
func mapGatewayListenerConfigsByPort(gw *gwv1.Gateway, routes map[int32][]routeutils.RouteDescriptor) (map[int32]*gwListenerConfig, error) {
492-
gwListenerConfigs := make(map[int32]*gwListenerConfig)
491+
func mapGatewayListenerConfigsByPort(gw *gwv1.Gateway, routes map[int32][]routeutils.RouteDescriptor) (map[int32]gwListenerConfig, error) {
492+
gwListenerConfigs := make(map[int32]gwListenerConfig)
493493
for _, listener := range gw.Spec.Listeners {
494494
port := int32(listener.Port)
495-
protocol := listener.Protocol
496-
if gwListenerConfigs[port] != nil && string(gwListenerConfigs[port].protocol) != string(protocol) {
497-
return nil, fmt.Errorf("invalid listeners on gateway, listeners with same ports cannot have different protocols")
495+
protocol := elbv2model.Protocol(listener.Protocol)
496+
497+
_, hasPort := gwListenerConfigs[port]
498+
if !hasPort {
499+
gwListenerConfigs[port] = gwListenerConfig{
500+
protocol: protocol,
501+
hostnames: sets.New[string](),
502+
}
498503
}
499-
if gwListenerConfigs[port] == nil {
500-
gwListenerConfigs[port] = &gwListenerConfig{
501-
protocol: elbv2model.Protocol(protocol),
504+
505+
if hasPort && gwListenerConfigs[port].protocol != protocol {
506+
// Special case TCP_UDP (or TCP_QUIC)
507+
508+
mergedValue, mergeErr := mergeProtocols(gwListenerConfigs[port].protocol, protocol)
509+
510+
if mergeErr != nil {
511+
return nil, fmt.Errorf("invalid listeners on gateway, listeners with same ports cannot have different protocols")
512+
}
513+
514+
// TODO this only works for TCP, UDP route merging.
515+
// If we need to support TLS merging, then this will need
516+
// to be updated.
517+
gwListenerConfigs[port] = gwListenerConfig{
518+
protocol: mergedValue,
502519
hostnames: sets.New[string](),
503520
}
504521
}
@@ -532,11 +549,11 @@ func mapGatewayListenerConfigsByPort(gw *gwv1.Gateway, routes map[int32][]routeu
532549

533550
// mapLoadBalancerListenerConfigsByPort creates a mapping of ports to their corresponding
534551
// listener configurations from the LoadBalancer configuration.
535-
func mapLoadBalancerListenerConfigsByPort(lbCfg elbv2gw.LoadBalancerConfiguration, gatewayListeners []gwv1.Listener) map[int32]*elbv2gw.ListenerConfiguration {
552+
func mapLoadBalancerListenerConfigsByPort(lbCfg elbv2gw.LoadBalancerConfiguration, gatewayListeners map[int32]gwListenerConfig) map[int32]*elbv2gw.ListenerConfiguration {
536553
configuredListeners := sets.NewString()
537554

538-
for _, configuredListener := range gatewayListeners {
539-
configuredListeners.Insert(generateListenerPortKey(configuredListener))
555+
for port, configuredListener := range gatewayListeners {
556+
configuredListeners.Insert(generateListenerPortKey(port, configuredListener))
540557
}
541558

542559
lbLsCfgs := make(map[int32]*elbv2gw.ListenerConfiguration)
@@ -554,8 +571,8 @@ func mapLoadBalancerListenerConfigsByPort(lbCfg elbv2gw.LoadBalancerConfiguratio
554571
return lbLsCfgs
555572
}
556573

557-
func generateListenerPortKey(listener gwv1.Listener) string {
558-
return fmt.Sprintf("%s:%d", strings.ToLower(string(listener.Protocol)), listener.Port)
574+
func generateListenerPortKey(port int32, listener gwListenerConfig) string {
575+
return fmt.Sprintf("%s:%d", strings.ToLower(string(listener.protocol)), port)
559576
}
560577

561578
func newListenerBuilder(loadBalancerType elbv2model.LoadBalancerType, tgBuilder targetGroupBuilder, tagHelper tagHelper, clusterName string, defaultSSLPolicy string, elbv2Client services.ELBV2, acmClient services.ACM, k8sClient client.Client, allowedCAARNs []string, secretsManager k8s.SecretsManager, logger logr.Logger) listenerBuilder {
@@ -599,3 +616,19 @@ func getRoutingAction(config *elbv2gw.ListenerRuleConfiguration) *elbv2gw.Action
599616
}
600617
return nil
601618
}
619+
620+
func mergeProtocols(storedProtocol, proposedProtocol elbv2model.Protocol) (elbv2model.Protocol, error) {
621+
if storedProtocol == elbv2model.ProtocolTCP_UDP && (proposedProtocol == elbv2model.ProtocolTCP || proposedProtocol == elbv2model.ProtocolUDP) {
622+
return elbv2model.ProtocolTCP_UDP, nil
623+
}
624+
625+
if storedProtocol == elbv2model.ProtocolTCP && proposedProtocol == elbv2model.ProtocolUDP {
626+
return elbv2model.ProtocolTCP_UDP, nil
627+
}
628+
629+
if storedProtocol == elbv2model.ProtocolUDP && proposedProtocol == elbv2model.ProtocolTCP {
630+
return elbv2model.ProtocolTCP_UDP, nil
631+
}
632+
633+
return elbv2model.ProtocolHTTP, errors.New("unsupported merge")
634+
}

0 commit comments

Comments
 (0)