Skip to content

Commit 198d48a

Browse files
authored
feat: support consistent hash for non-route backends (#9231)
* support consistent hash for non-route backends Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com> * update e2e tests Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com> --------- Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com>
1 parent 8b2e277 commit 198d48a

11 files changed

Lines changed: 93 additions & 7 deletions

internal/xds/translator/cluster.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
clusterv3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
1616
corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
1717
endpointv3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
18+
routev3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
1819
commondnsv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/clusters/common/dns/v3"
1920
dnsclusterv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/clusters/dns/v3"
2021
dfpv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/clusters/dynamic_forward_proxy/v3"
@@ -1091,13 +1092,22 @@ func buildTypedExtensionProtocolOptions(args *xdsClusterArgs, requiresAutoHTTPCo
10911092
requiresHTTPFilters := (len(args.settings) > 0 && args.settings[0].Filters != nil && args.settings[0].Filters.CredentialInjection != nil) ||
10921093
args.admissionControl != nil
10931094

1095+
var clusterHashPolicy []*routev3.RouteAction_HashPolicy
1096+
if !args.isRoute && args.loadBalancer != nil {
1097+
clusterHashPolicy = buildConsistentHashPolicy(args.loadBalancer.ConsistentHash)
1098+
}
1099+
10941100
requiredHTTPProtocolOptions := args.useClientProtocol || requiresAutoHTTPConfig ||
1095-
requiresCommonHTTPOptions || requiresHTTP1Options || requiresHTTP2Options || requiresHTTPFilters || requiresAutoSNI || forceHTTP1UpstreamProtocol
1101+
requiresCommonHTTPOptions || requiresHTTP1Options || requiresHTTP2Options || requiresHTTPFilters || requiresAutoSNI ||
1102+
forceHTTP1UpstreamProtocol || len(clusterHashPolicy) > 0
10961103

10971104
if !requiredHTTPProtocolOptions {
10981105
return nil, nil, nil
10991106
}
11001107
protocolOptions := httpv3.HttpProtocolOptions{}
1108+
if len(clusterHashPolicy) > 0 {
1109+
protocolOptions.HashPolicy = clusterHashPolicy
1110+
}
11011111
if requiresCommonHTTPOptions {
11021112
protocolOptions.CommonHttpProtocolOptions = &corev3.HttpProtocolOptions{}
11031113
if args.timeout != nil && args.timeout.HTTP != nil {

internal/xds/translator/cluster_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
cswrrv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3"
1818
override_hostv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/override_host/v3"
1919
wrr_localityv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/wrr_locality/v3"
20+
httpv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/upstreams/http/v3"
2021
"github.com/google/go-cmp/cmp"
2122
"github.com/stretchr/testify/require"
2223
"google.golang.org/protobuf/encoding/protojson"
@@ -295,6 +296,53 @@ func TestBuildClusterWithBackendUtilization(t *testing.T) {
295296
require.Equal(t, "type.googleapis.com/envoy.extensions.load_balancing_policies.client_side_weighted_round_robin.v3.ClientSideWeightedRoundRobin", policy.TypedExtensionConfig.TypedConfig.TypeUrl)
296297
}
297298

299+
func TestBuildXdsClusterWithClusterLevelHashPolicy(t *testing.T) {
300+
sourceIP := true
301+
args := &xdsClusterArgs{
302+
name: "test-cluster-consistent-hash",
303+
endpointType: EndpointTypeStatic,
304+
settings: []*ir.DestinationSetting{{
305+
Endpoints: []*ir.DestinationEndpoint{{Host: "127.0.0.1", Port: 8080}},
306+
}},
307+
loadBalancer: &ir.LoadBalancer{
308+
ConsistentHash: &ir.ConsistentHash{
309+
SourceIP: &sourceIP,
310+
},
311+
},
312+
}
313+
314+
result, err := buildXdsCluster(args)
315+
require.NoError(t, err)
316+
317+
options := &httpv3.HttpProtocolOptions{}
318+
require.NotNil(t, result.cluster.TypedExtensionProtocolOptions)
319+
require.NoError(t, result.cluster.TypedExtensionProtocolOptions[extensionOptionsKey].UnmarshalTo(options))
320+
require.Len(t, options.HashPolicy, 1)
321+
require.True(t, options.HashPolicy[0].GetConnectionProperties().GetSourceIp())
322+
}
323+
324+
func TestBuildXdsRouteClusterWithoutClusterLevelHashPolicy(t *testing.T) {
325+
sourceIP := true
326+
args := &xdsClusterArgs{
327+
name: "test-route-cluster-consistent-hash",
328+
endpointType: EndpointTypeStatic,
329+
settings: []*ir.DestinationSetting{{
330+
Endpoints: []*ir.DestinationEndpoint{{Host: "127.0.0.1", Port: 8080}},
331+
}},
332+
loadBalancer: &ir.LoadBalancer{
333+
ConsistentHash: &ir.ConsistentHash{
334+
SourceIP: &sourceIP,
335+
},
336+
},
337+
isRoute: true,
338+
}
339+
340+
result, err := buildXdsCluster(args)
341+
require.NoError(t, err)
342+
343+
require.Nil(t, result.cluster.TypedExtensionProtocolOptions)
344+
}
345+
298346
func TestBuildClusterWithBackendUtilizationSlowStart(t *testing.T) {
299347
window := 5 * time.Second
300348
args := &xdsClusterArgs{

internal/xds/translator/route.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,13 @@ func buildHashPolicy(httpRoute *ir.HTTPRoute) []*routev3.RouteAction_HashPolicy
708708
return nil
709709
}
710710

711-
ch := httpRoute.Traffic.LoadBalancer.ConsistentHash
711+
return buildConsistentHashPolicy(httpRoute.Traffic.LoadBalancer.ConsistentHash)
712+
}
713+
714+
func buildConsistentHashPolicy(ch *ir.ConsistentHash) []*routev3.RouteAction_HashPolicy {
715+
if ch == nil {
716+
return nil
717+
}
712718

713719
switch {
714720
case ch.Headers != nil:

internal/xds/translator/testdata/in/xds-ir/ext-auth-retry.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ http:
2929
extAuth:
3030
name: securitypolicy/default/policy-for-http-route-1
3131
traffic:
32+
loadBalancer:
33+
consistentHash:
34+
sourceIP: true
3235
retry:
3336
numRetries: 2
3437
perRetry:
@@ -86,6 +89,9 @@ http:
8689
extAuth:
8790
name: securitypolicy/default/policy-for-http-route-1
8891
traffic:
92+
loadBalancer:
93+
consistentHash:
94+
sourceIP: true
8995
retry:
9096
numRetries: 2
9197
perRetry:

internal/xds/translator/testdata/out/xds-ir/ext-auth-retry.clusters.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,9 @@
8282
loadBalancingPolicy:
8383
policies:
8484
- typedExtensionConfig:
85-
name: envoy.load_balancing_policies.least_request
85+
name: envoy.load_balancing_policies.maglev
8686
typedConfig:
87-
'@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest
88-
localityLbConfig:
89-
localityWeightedLbConfig: {}
87+
'@type': type.googleapis.com/envoy.extensions.load_balancing_policies.maglev.v3.Maglev
9088
name: securitypolicy/default/policy-for-http-route-1/default/grpc-backend
9189
perConnectionBufferLimitBytes: 32768
9290
type: EDS
@@ -97,6 +95,9 @@
9795
http2ProtocolOptions:
9896
initialConnectionWindowSize: 1048576
9997
initialStreamWindowSize: 65536
98+
hashPolicy:
99+
- connectionProperties:
100+
sourceIp: true
100101
- circuitBreakers:
101102
thresholds:
102103
- maxRetries: 1024

internal/xds/translator/testdata/out/xds-ir/jwt-with-backend-tls-retry.clusters.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@
129129
idleTimeout: 16s
130130
maxConnectionDuration: 17s
131131
maxRequestsPerConnection: 1
132+
hashPolicy:
133+
- connectionProperties:
134+
sourceIp: true
132135
upstreamConnectionOptions:
133136
tcpKeepalive:
134137
keepaliveInterval: 60

internal/xds/translator/testdata/out/xds-ir/oidc-backend-cluster-provider.clusters.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@
129129
idleTimeout: 16s
130130
maxConnectionDuration: 17s
131131
maxRequestsPerConnection: 1
132+
hashPolicy:
133+
- connectionProperties:
134+
sourceIp: true
132135
upstreamConnectionOptions:
133136
tcpKeepalive:
134137
keepaliveInterval: 60

internal/xds/translator/testdata/out/xds-ir/oidc-provider-traffic-features.clusters.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@
107107
maxRequestsPerConnection: 1
108108
explicitHttpConfig:
109109
httpProtocolOptions: {}
110+
hashPolicy:
111+
- connectionProperties:
112+
sourceIp: true
110113
upstreamConnectionOptions:
111114
tcpKeepalive:
112115
keepaliveInterval: 60
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed `ConsistentHash` load balancer settings on non-route service clusters, such as SecurityPolicy extAuth backends, by emitting cluster-level HTTP hash policies.

test/e2e/testdata/ext-auth-grpc-securitypolicy.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ spec:
5454
- name: grpc-ext-auth
5555
namespace: gateway-conformance-infra
5656
port: 9002
57+
backendSettings:
58+
loadBalancer:
59+
type: ConsistentHash
60+
consistentHash:
61+
type: SourceIP
5762
---
5863
apiVersion: gateway.networking.k8s.io/v1
5964
kind: BackendTLSPolicy

0 commit comments

Comments
 (0)