Skip to content

Commit 04cf90a

Browse files
authored
xds: support for updating upstreamTlsContext and SslContextProvider, also release object in SdsProtocolNegotiators (#6599)
1 parent 066e72d commit 04cf90a

9 files changed

+278
-119
lines changed

xds/src/main/java/io/grpc/xds/CdsLoadBalancer.java

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
import io.grpc.xds.XdsClient.ClusterWatcher;
4141
import io.grpc.xds.XdsLoadBalancerProvider.XdsConfig;
4242
import io.grpc.xds.XdsSubchannelPickers.ErrorPicker;
43+
import io.grpc.xds.sds.SslContextProvider;
44+
import io.grpc.xds.sds.TlsContextManager;
45+
import io.grpc.xds.sds.TlsContextManagerImpl;
4346
import java.util.ArrayList;
4447
import java.util.List;
4548
import java.util.Map;
@@ -55,6 +58,7 @@ public final class CdsLoadBalancer extends LoadBalancer {
5558
private final LoadBalancerRegistry lbRegistry;
5659
private final GracefulSwitchLoadBalancer switchingLoadBalancer;
5760
private final Helper helper;
61+
private final TlsContextManager tlsContextManager;
5862

5963
// The following fields become non-null once handleResolvedAddresses() successfully.
6064

@@ -70,15 +74,17 @@ public final class CdsLoadBalancer extends LoadBalancer {
7074
private XdsClient xdsClient;
7175

7276
CdsLoadBalancer(Helper helper) {
73-
this(helper, LoadBalancerRegistry.getDefaultRegistry());
77+
this(helper, LoadBalancerRegistry.getDefaultRegistry(), TlsContextManagerImpl.getInstance());
7478
}
7579

7680
@VisibleForTesting
77-
CdsLoadBalancer(Helper helper, LoadBalancerRegistry lbRegistry) {
81+
CdsLoadBalancer(Helper helper, LoadBalancerRegistry lbRegistry,
82+
TlsContextManager tlsContextManager) {
7883
this.helper = helper;
7984
this.channelLogger = helper.getChannelLogger();
8085
this.lbRegistry = lbRegistry;
8186
this.switchingLoadBalancer = new GracefulSwitchLoadBalancer(helper);
87+
this.tlsContextManager = tlsContextManager;
8288
}
8389

8490
@Override
@@ -236,22 +242,23 @@ public void handleResolvedAddresses(ResolvedAddresses resolvedAddresses) {
236242

237243
private static final class EdsLoadBalancingHelper extends ForwardingLoadBalancerHelper {
238244
private final Helper delegate;
239-
private final AtomicReference<UpstreamTlsContext> upstreamTlsContext;
245+
private final AtomicReference<SslContextProvider<UpstreamTlsContext>> sslContextProvider;
240246

241-
EdsLoadBalancingHelper(Helper helper, AtomicReference<UpstreamTlsContext> upstreamTlsContext) {
247+
EdsLoadBalancingHelper(Helper helper,
248+
AtomicReference<SslContextProvider<UpstreamTlsContext>> sslContextProvider) {
242249
this.delegate = helper;
243-
this.upstreamTlsContext = upstreamTlsContext;
250+
this.sslContextProvider = sslContextProvider;
244251
}
245252

246253
@Override
247254
public Subchannel createSubchannel(CreateSubchannelArgs createSubchannelArgs) {
248-
if (upstreamTlsContext.get() != null) {
255+
if (sslContextProvider.get() != null) {
249256
createSubchannelArgs =
250257
createSubchannelArgs
251258
.toBuilder()
252259
.setAddresses(
253260
addUpstreamTlsContext(createSubchannelArgs.getAddresses(),
254-
upstreamTlsContext.get()))
261+
sslContextProvider.get().getSource()))
255262
.build();
256263
}
257264
return delegate.createSubchannel(createSubchannelArgs);
@@ -295,7 +302,8 @@ private final class ClusterWatcherImpl implements ClusterWatcher {
295302
LoadBalancer edsBalancer;
296303

297304
ClusterWatcherImpl(Helper helper, ResolvedAddresses resolvedAddresses) {
298-
this.helper = new EdsLoadBalancingHelper(helper, new AtomicReference<UpstreamTlsContext>());
305+
this.helper = new EdsLoadBalancingHelper(helper,
306+
new AtomicReference<SslContextProvider<UpstreamTlsContext>>());
299307
this.resolvedAddresses = resolvedAddresses;
300308
}
301309

@@ -312,8 +320,7 @@ public void onClusterChanged(ClusterUpdate newUpdate) {
312320
/* fallbackPolicy = */ null,
313321
/* edsServiceName = */ newUpdate.getEdsServiceName(),
314322
/* lrsServerName = */ newUpdate.getLrsServerName());
315-
UpstreamTlsContext upstreamTlsContext = newUpdate.getUpstreamTlsContext();
316-
helper.upstreamTlsContext.set(upstreamTlsContext);
323+
updateSslContextProvider(newUpdate.getUpstreamTlsContext());
317324
if (edsBalancer == null) {
318325
edsBalancer = lbRegistry.getProvider(XDS_POLICY_NAME).newLoadBalancer(helper);
319326
}
@@ -327,6 +334,27 @@ public void onClusterChanged(ClusterUpdate newUpdate) {
327334
.build());
328335
}
329336

337+
/** For new UpstreamTlsContext value, release old SslContextProvider. */
338+
private void updateSslContextProvider(UpstreamTlsContext newUpstreamTlsContext) {
339+
SslContextProvider<UpstreamTlsContext> oldSslContextProvider =
340+
helper.sslContextProvider.get();
341+
if (oldSslContextProvider != null) {
342+
UpstreamTlsContext oldUpstreamTlsContext = oldSslContextProvider.getSource();
343+
344+
if (oldUpstreamTlsContext.equals(newUpstreamTlsContext)) {
345+
return;
346+
}
347+
tlsContextManager.releaseClientSslContextProvider(oldSslContextProvider);
348+
}
349+
if (newUpstreamTlsContext != null) {
350+
SslContextProvider<UpstreamTlsContext> newSslContextProvider =
351+
tlsContextManager.findOrCreateClientSslContextProvider(newUpstreamTlsContext);
352+
helper.sslContextProvider.set(newSslContextProvider);
353+
} else {
354+
helper.sslContextProvider.set(null);
355+
}
356+
}
357+
330358
@Override
331359
public void onError(Status error) {
332360
channelLogger.log(ChannelLogLevel.ERROR, "CDS load balancer received an error: {0}", error);

xds/src/main/java/io/grpc/xds/sds/SslContextProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ protected SslContextProvider(K source, boolean server) {
5555
this.server = server;
5656
}
5757

58-
K getSource() {
58+
public K getSource() {
5959
return source;
6060
}
6161

Lines changed: 10 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019 The gRPC Authors
2+
* Copyright 2020 The gRPC Authors
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,63 +16,20 @@
1616

1717
package io.grpc.xds.sds;
1818

19-
import static com.google.common.base.Preconditions.checkNotNull;
20-
21-
import com.google.common.annotations.VisibleForTesting;
2219
import io.envoyproxy.envoy.api.v2.auth.DownstreamTlsContext;
2320
import io.envoyproxy.envoy.api.v2.auth.UpstreamTlsContext;
2421
import io.grpc.Internal;
25-
import io.grpc.xds.sds.ReferenceCountingSslContextProviderMap.SslContextProviderFactory;
2622

27-
/**
28-
* Class to manage {@link SslContextProvider} objects created from inputs we get from xDS. Used by
29-
* gRPC-xds to access the SslContext's and is not public API. This manager manages the life-cycle of
30-
* {@link SslContextProvider} objects as shared resources via ref-counting as described in {@link
31-
* ReferenceCountingSslContextProviderMap}.
32-
*/
3323
@Internal
34-
public final class TlsContextManager {
35-
36-
private static TlsContextManager instance;
37-
38-
private final ReferenceCountingSslContextProviderMap<UpstreamTlsContext> mapForClients;
39-
private final ReferenceCountingSslContextProviderMap<DownstreamTlsContext> mapForServers;
40-
41-
private TlsContextManager() {
42-
this(new ClientSslContextProviderFactory(), new ServerSslContextProviderFactory());
43-
}
44-
45-
@VisibleForTesting
46-
TlsContextManager(
47-
SslContextProviderFactory<UpstreamTlsContext> clientFactory,
48-
SslContextProviderFactory<DownstreamTlsContext> serverFactory) {
49-
checkNotNull(clientFactory, "clientFactory");
50-
checkNotNull(serverFactory, "serverFactory");
51-
mapForClients = new ReferenceCountingSslContextProviderMap<>(clientFactory);
52-
mapForServers = new ReferenceCountingSslContextProviderMap<>(serverFactory);
53-
}
54-
55-
/** Gets the TlsContextManager singleton. */
56-
public static synchronized TlsContextManager getInstance() {
57-
if (instance == null) {
58-
instance = new TlsContextManager();
59-
}
60-
return instance;
61-
}
24+
public interface TlsContextManager {
6225

6326
/** Creates a SslContextProvider. Used for retrieving a server-side SslContext. */
64-
public SslContextProvider<DownstreamTlsContext> findOrCreateServerSslContextProvider(
65-
DownstreamTlsContext downstreamTlsContext) {
66-
checkNotNull(downstreamTlsContext, "downstreamTlsContext");
67-
return mapForServers.get(downstreamTlsContext);
68-
}
27+
SslContextProvider<DownstreamTlsContext> findOrCreateServerSslContextProvider(
28+
DownstreamTlsContext downstreamTlsContext);
6929

7030
/** Creates a SslContextProvider. Used for retrieving a client-side SslContext. */
71-
public SslContextProvider<UpstreamTlsContext> findOrCreateClientSslContextProvider(
72-
UpstreamTlsContext upstreamTlsContext) {
73-
checkNotNull(upstreamTlsContext, "upstreamTlsContext");
74-
return mapForClients.get(upstreamTlsContext);
75-
}
31+
SslContextProvider<UpstreamTlsContext> findOrCreateClientSslContextProvider(
32+
UpstreamTlsContext upstreamTlsContext);
7633

7734
/**
7835
* Releases an instance of the given client-side {@link SslContextProvider}.
@@ -83,11 +40,8 @@ public SslContextProvider<UpstreamTlsContext> findOrCreateClientSslContextProvid
8340
* <p>Caller must not release a reference more than once. It's advised that you clear the
8441
* reference to the instance with the null returned by this method.
8542
*/
86-
public SslContextProvider<UpstreamTlsContext> releaseClientSslContextProvider(
87-
SslContextProvider<UpstreamTlsContext> sslContextProvider) {
88-
checkNotNull(sslContextProvider, "sslContextProvider");
89-
return mapForClients.release(sslContextProvider);
90-
}
43+
SslContextProvider<UpstreamTlsContext> releaseClientSslContextProvider(
44+
SslContextProvider<UpstreamTlsContext> sslContextProvider);
9145

9246
/**
9347
* Releases an instance of the given server-side {@link SslContextProvider}.
@@ -98,9 +52,6 @@ public SslContextProvider<UpstreamTlsContext> releaseClientSslContextProvider(
9852
* <p>Caller must not release a reference more than once. It's advised that you clear the
9953
* reference to the instance with the null returned by this method.
10054
*/
101-
public SslContextProvider<DownstreamTlsContext> releaseServerSslContextProvider(
102-
SslContextProvider<DownstreamTlsContext> sslContextProvider) {
103-
checkNotNull(sslContextProvider, "sslContextProvider");
104-
return mapForServers.release(sslContextProvider);
105-
}
55+
SslContextProvider<DownstreamTlsContext> releaseServerSslContextProvider(
56+
SslContextProvider<DownstreamTlsContext> sslContextProvider);
10657
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2019 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc.xds.sds;
18+
19+
import static com.google.common.base.Preconditions.checkNotNull;
20+
21+
import com.google.common.annotations.VisibleForTesting;
22+
import io.envoyproxy.envoy.api.v2.auth.DownstreamTlsContext;
23+
import io.envoyproxy.envoy.api.v2.auth.UpstreamTlsContext;
24+
import io.grpc.Internal;
25+
import io.grpc.xds.sds.ReferenceCountingSslContextProviderMap.SslContextProviderFactory;
26+
27+
/**
28+
* Class to manage {@link SslContextProvider} objects created from inputs we get from xDS. Used by
29+
* gRPC-xds to access the SslContext's and is not public API. This manager manages the life-cycle of
30+
* {@link SslContextProvider} objects as shared resources via ref-counting as described in {@link
31+
* ReferenceCountingSslContextProviderMap}.
32+
*/
33+
@Internal
34+
public final class TlsContextManagerImpl implements TlsContextManager {
35+
36+
private static TlsContextManagerImpl instance;
37+
38+
private final ReferenceCountingSslContextProviderMap<UpstreamTlsContext> mapForClients;
39+
private final ReferenceCountingSslContextProviderMap<DownstreamTlsContext> mapForServers;
40+
41+
private TlsContextManagerImpl() {
42+
this(new ClientSslContextProviderFactory(), new ServerSslContextProviderFactory());
43+
}
44+
45+
@VisibleForTesting
46+
TlsContextManagerImpl(
47+
SslContextProviderFactory<UpstreamTlsContext> clientFactory,
48+
SslContextProviderFactory<DownstreamTlsContext> serverFactory) {
49+
checkNotNull(clientFactory, "clientFactory");
50+
checkNotNull(serverFactory, "serverFactory");
51+
mapForClients = new ReferenceCountingSslContextProviderMap<>(clientFactory);
52+
mapForServers = new ReferenceCountingSslContextProviderMap<>(serverFactory);
53+
}
54+
55+
/** Gets the TlsContextManagerImpl singleton. */
56+
public static synchronized TlsContextManagerImpl getInstance() {
57+
if (instance == null) {
58+
instance = new TlsContextManagerImpl();
59+
}
60+
return instance;
61+
}
62+
63+
@Override
64+
public SslContextProvider<DownstreamTlsContext> findOrCreateServerSslContextProvider(
65+
DownstreamTlsContext downstreamTlsContext) {
66+
checkNotNull(downstreamTlsContext, "downstreamTlsContext");
67+
return mapForServers.get(downstreamTlsContext);
68+
}
69+
70+
@Override
71+
public SslContextProvider<UpstreamTlsContext> findOrCreateClientSslContextProvider(
72+
UpstreamTlsContext upstreamTlsContext) {
73+
checkNotNull(upstreamTlsContext, "upstreamTlsContext");
74+
return mapForClients.get(upstreamTlsContext);
75+
}
76+
77+
@Override
78+
public SslContextProvider<UpstreamTlsContext> releaseClientSslContextProvider(
79+
SslContextProvider<UpstreamTlsContext> sslContextProvider) {
80+
checkNotNull(sslContextProvider, "sslContextProvider");
81+
return mapForClients.release(sslContextProvider);
82+
}
83+
84+
@Override
85+
public SslContextProvider<DownstreamTlsContext> releaseServerSslContextProvider(
86+
SslContextProvider<DownstreamTlsContext> sslContextProvider) {
87+
checkNotNull(sslContextProvider, "sslContextProvider");
88+
return mapForServers.release(sslContextProvider);
89+
}
90+
}

xds/src/main/java/io/grpc/xds/sds/internal/SdsProtocolNegotiators.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
import io.grpc.netty.NettyChannelBuilder;
3232
import io.grpc.xds.XdsAttributes;
3333
import io.grpc.xds.sds.SslContextProvider;
34-
import io.grpc.xds.sds.TlsContextManager;
34+
import io.grpc.xds.sds.TlsContextManagerImpl;
3535
import io.netty.channel.ChannelHandler;
3636
import io.netty.channel.ChannelHandlerAdapter;
3737
import io.netty.channel.ChannelHandlerContext;
@@ -207,8 +207,9 @@ protected void handlerAdded0(final ChannelHandlerContext ctx) {
207207
final BufferReadsHandler bufferReads = new BufferReadsHandler();
208208
ctx.pipeline().addBefore(ctx.name(), null, bufferReads);
209209

210-
SslContextProvider<UpstreamTlsContext> sslContextProvider =
211-
TlsContextManager.getInstance().findOrCreateClientSslContextProvider(upstreamTlsContext);
210+
final SslContextProvider<UpstreamTlsContext> sslContextProvider =
211+
TlsContextManagerImpl.getInstance()
212+
.findOrCreateClientSslContextProvider(upstreamTlsContext);
212213

213214
sslContextProvider.addCallback(
214215
new SslContextProvider.Callback() {
@@ -226,6 +227,8 @@ public void updateSecret(SslContext sslContext) {
226227
ctx.pipeline().addAfter(ctx.name(), null, handler);
227228
fireProtocolNegotiationEvent(ctx);
228229
ctx.pipeline().remove(bufferReads);
230+
TlsContextManagerImpl.getInstance()
231+
.releaseClientSslContextProvider(sslContextProvider);
229232
}
230233

231234
@Override
@@ -303,8 +306,8 @@ protected void handlerAdded0(final ChannelHandlerContext ctx) {
303306
final BufferReadsHandler bufferReads = new BufferReadsHandler();
304307
ctx.pipeline().addBefore(ctx.name(), null, bufferReads);
305308

306-
SslContextProvider<DownstreamTlsContext> sslContextProvider =
307-
TlsContextManager.getInstance()
309+
final SslContextProvider<DownstreamTlsContext> sslContextProvider =
310+
TlsContextManagerImpl.getInstance()
308311
.findOrCreateServerSslContextProvider(downstreamTlsContext);
309312

310313
sslContextProvider.addCallback(
@@ -319,6 +322,8 @@ public void updateSecret(SslContext sslContext) {
319322
ctx.pipeline().addAfter(ctx.name(), null, handler);
320323
fireProtocolNegotiationEvent(ctx);
321324
ctx.pipeline().remove(bufferReads);
325+
TlsContextManagerImpl.getInstance()
326+
.releaseServerSslContextProvider(sslContextProvider);
322327
}
323328

324329
@Override

xds/src/main/java/io/grpc/xds/sds/trust/SdsTrustManagerFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@
4141
import javax.net.ssl.X509ExtendedTrustManager;
4242

4343
/**
44-
* Factory class used by providers of {@link io.grpc.xds.sds.TlsContextManager} to provide a {@link
45-
* SdsX509TrustManager} for trust and SAN checks.
44+
* Factory class used by providers of {@link io.grpc.xds.sds.TlsContextManagerImpl} to provide a
45+
* {@link SdsX509TrustManager} for trust and SAN checks.
4646
*/
4747
@Internal
4848
public final class SdsTrustManagerFactory extends SimpleTrustManagerFactory {

0 commit comments

Comments
 (0)