diff --git a/internal/gatewayapi/translator.go b/internal/gatewayapi/translator.go index 5163deca337..dd463d201aa 100644 --- a/internal/gatewayapi/translator.go +++ b/internal/gatewayapi/translator.go @@ -247,6 +247,7 @@ func (t *Translator) InitIRs(gateways []*GatewayContext, resources *Resources) ( if isMergeGatewaysEnabled(resources) { t.MergeGateways = true + gwXdsIR.MergeGateways = true irKey = string(t.GatewayClassName) maps.Copy(labels, GatewayClassOwnerLabel(string(t.GatewayClassName))) diff --git a/internal/infrastructure/kubernetes/proxy/resource_provider.go b/internal/infrastructure/kubernetes/proxy/resource_provider.go index 7faccb252ea..5044d83450e 100644 --- a/internal/infrastructure/kubernetes/proxy/resource_provider.go +++ b/internal/infrastructure/kubernetes/proxy/resource_provider.go @@ -67,31 +67,38 @@ func (r *ResourceRender) ServiceAccount() (*corev1.ServiceAccount, error) { // Service returns the expected Service based on the provided infra. func (r *ResourceRender) Service() (*corev1.Service, error) { var ports []corev1.ServicePort + configuredPorts := map[int32]bool{} for _, listener := range r.infra.Listeners { for _, port := range listener.Ports { target := intstr.IntOrString{IntVal: port.ContainerPort} - protocol := corev1.ProtocolTCP - if port.Protocol == ir.UDPProtocolType { - protocol = corev1.ProtocolUDP - } - - p := corev1.ServicePort{ - Name: ExpectedResourceHashedName(port.Name), - Protocol: protocol, - Port: port.ServicePort, - TargetPort: target, - } - ports = append(ports, p) + if alreadyHasHttp3, found := configuredPorts[port.ContainerPort]; !found || !alreadyHasHttp3 { + if !found { + protocol := corev1.ProtocolTCP + if port.Protocol == ir.UDPProtocolType { + protocol = corev1.ProtocolUDP + } - if port.Protocol == ir.HTTPSProtocolType { - if listener.HTTP3 != nil { p := corev1.ServicePort{ - Name: ExpectedResourceHashedName(port.Name + "-h3"), - Protocol: corev1.ProtocolUDP, + Name: ExpectedResourceHashedName(port.Name), + Protocol: protocol, Port: port.ServicePort, TargetPort: target, } ports = append(ports, p) + configuredPorts[port.ServicePort] = false + } + + if port.Protocol == ir.HTTPSProtocolType { + if listener.HTTP3 != nil && !alreadyHasHttp3 { + p := corev1.ServicePort{ + Name: ExpectedResourceHashedName(port.Name + "-h3"), + Protocol: corev1.ProtocolUDP, + Port: port.ServicePort, + TargetPort: target, + } + ports = append(ports, p) + configuredPorts[port.ServicePort] = true + } } } } diff --git a/internal/ir/xds.go b/internal/ir/xds.go index d501fffac8f..ce6921165ae 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -81,6 +81,8 @@ type Xds struct { UDP []*UDPListener `json:"udp,omitempty" yaml:"udp,omitempty"` // EnvoyPatchPolicies is the intermediate representation of the EnvoyPatchPolicy resource EnvoyPatchPolicies []*EnvoyPatchPolicy `json:"envoyPatchPolicies,omitempty" yaml:"envoyPatchPolicies,omitempty"` + // MergeGateways indicates if this IR should be translated to work in the merged gateways scenario + MergeGateways bool `json:"mergeGateways,omitempty" yaml:"mergeGateways,omitempty"` } // Equal implements the Comparable interface used by watchable.DeepEqual to skip unnecessary updates. diff --git a/internal/xds/translator/listener.go b/internal/xds/translator/listener.go index 08287738a1c..7fbf8a37682 100644 --- a/internal/xds/translator/listener.go +++ b/internal/xds/translator/listener.go @@ -183,7 +183,7 @@ func buildXdsQuicListener(name, address string, port uint32, accesslog *ir.Acces } func (t *Translator) addXdsHTTPFilterChain(xdsListener *listenerv3.Listener, irListener *ir.HTTPListener, - accesslog *ir.AccessLog, tracing *ir.Tracing, http3Listener bool) error { + accesslog *ir.AccessLog, tracing *ir.Tracing, http3Listener bool, mergeGateways bool) error { al := buildXdsAccessLog(accesslog, false) hcmTracing, err := buildHCMTracing(tracing) @@ -274,20 +274,22 @@ func (t *Translator) addXdsHTTPFilterChain(xdsListener *listenerv3.Listener, irL }}, } - if irListener.TLS != nil { - var tSocket *corev3.TransportSocket - if http3Listener { - tSocket, err = buildDownstreamQUICTransportSocket(irListener.TLS) - if err != nil { - return err - } - } else { - tSocket, err = buildXdsDownstreamTLSSocket(irListener.TLS) - if err != nil { - return err + if irListener.TLS != nil || mergeGateways { + if irListener.TLS != nil { + var tSocket *corev3.TransportSocket + if http3Listener { + tSocket, err = buildDownstreamQUICTransportSocket(irListener.TLS) + if err != nil { + return err + } + } else { + tSocket, err = buildXdsDownstreamTLSSocket(irListener.TLS) + if err != nil { + return err + } } + filterChain.TransportSocket = tSocket } - filterChain.TransportSocket = tSocket if err := addServerNamesMatch(xdsListener, filterChain, irListener.Hostnames); err != nil { return err } diff --git a/internal/xds/translator/translator.go b/internal/xds/translator/translator.go index 4ce82ca543f..8229be97625 100644 --- a/internal/xds/translator/translator.go +++ b/internal/xds/translator/translator.go @@ -77,7 +77,7 @@ func (t *Translator) Translate(ir *ir.Xds) (*types.ResourceVersionTable, error) // to collect all errors and reflect them in the status of the CRDs. var errs error if err := t.processHTTPListenerXdsTranslation( - tCtx, ir.HTTP, ir.AccessLog, ir.Tracing, ir.Metrics); err != nil { + tCtx, ir.HTTP, ir.AccessLog, ir.Tracing, ir.Metrics, ir.MergeGateways); err != nil { errs = errors.Join(errs, err) } @@ -115,12 +115,12 @@ func (t *Translator) processHTTPListenerXdsTranslation( accessLog *ir.AccessLog, tracing *ir.Tracing, metrics *ir.Metrics, + mergeGateways bool, ) error { // The XDS translation is done in a best-effort manner, so we collect all // errors and return them at the end. var errs error for _, httpListener := range httpListeners { - addFilterChain := true var xdsRouteCfg *routev3.RouteConfiguration // Search for an existing listener, if it does not exist, create one. @@ -149,7 +149,6 @@ func (t *Translator) processHTTPListenerXdsTranslation( // If an existing listener exists, dont create a new filter chain // for HTTP traffic, match on the Domains field within VirtualHosts // within the same RouteConfiguration instead - addFilterChain = false xdsRouteCfg = findXdsRouteConfig(tCtx, routeName) if xdsRouteCfg == nil { // skip this listener if failed to find xds route config @@ -159,15 +158,13 @@ func (t *Translator) processHTTPListenerXdsTranslation( } } - if addFilterChain { - if err := t.addXdsHTTPFilterChain(xdsListener, httpListener, accessLog, tracing, false); err != nil { + if err := t.addXdsHTTPFilterChain(xdsListener, httpListener, accessLog, tracing, false, mergeGateways); err != nil { + return err + } + if enabledHTTP3 { + if err := t.addXdsHTTPFilterChain(quicXDSListener, httpListener, accessLog, tracing, true, mergeGateways); err != nil { return err } - if enabledHTTP3 { - if err := t.addXdsHTTPFilterChain(quicXDSListener, httpListener, accessLog, tracing, true); err != nil { - return err - } - } } // Create a route config if we have not found one yet