xds: implement the new filterChainMatch algorithm (#7910)

This commit is contained in:
sanjaypujare 2021-02-19 15:29:27 -08:00 committed by GitHub
parent a55e034732
commit 6a581f282b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1260 additions and 485 deletions

View File

@ -18,7 +18,7 @@ package io.grpc.xds;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.grpc.xds.EnvoyProtoData.TRANSPORT_SOCKET_NAME_TLS;
import static io.grpc.xds.EnvoyServerProtoData.TRANSPORT_SOCKET_NAME_TLS;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CaseFormat;

View File

@ -47,7 +47,6 @@ import javax.annotation.Nullable;
*/
// TODO(chengyuanzhang): put data types into smaller categories.
final class EnvoyProtoData {
static final String TRANSPORT_SOCKET_NAME_TLS = "envoy.transport_sockets.tls";
// Prevent instantiation.
private EnvoyProtoData() {

View File

@ -16,15 +16,16 @@
package io.grpc.xds;
import static io.grpc.xds.EnvoyProtoData.TRANSPORT_SOCKET_NAME_TLS;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.protobuf.Any;
import com.google.protobuf.InvalidProtocolBufferException;
import io.envoyproxy.envoy.config.core.v3.Address;
import io.envoyproxy.envoy.config.core.v3.SocketAddress;
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext;
import io.grpc.Internal;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -38,6 +39,8 @@ import javax.annotation.Nullable;
@Internal
public final class EnvoyServerProtoData {
static final String TRANSPORT_SOCKET_NAME_TLS = "envoy.transport_sockets.tls";
// Prevent instantiation.
private EnvoyServerProtoData() {
}
@ -144,21 +147,25 @@ public final class EnvoyServerProtoData {
}
static final class CidrRange {
private final String addressPrefix;
private final InetAddress addressPrefix;
private final int prefixLen;
@VisibleForTesting
CidrRange(String addressPrefix, int prefixLen) {
this.addressPrefix = addressPrefix;
CidrRange(String addressPrefix, int prefixLen) throws InvalidProtocolBufferException {
try {
this.addressPrefix = InetAddress.getByName(addressPrefix);
} catch (UnknownHostException e) {
throw new InvalidProtocolBufferException(e.getMessage());
}
this.prefixLen = prefixLen;
}
static CidrRange fromEnvoyProtoCidrRange(
io.envoyproxy.envoy.config.core.v3.CidrRange proto) {
io.envoyproxy.envoy.config.core.v3.CidrRange proto) throws InvalidProtocolBufferException {
return new CidrRange(proto.getAddressPrefix(), proto.getPrefixLen().getValue());
}
public String getAddressPrefix() {
public InetAddress getAddressPrefix() {
return addressPrefix;
}
@ -193,6 +200,17 @@ public final class EnvoyServerProtoData {
}
}
enum ConnectionSourceType {
// Any connection source matches.
ANY,
// Match a connection originating from the same host.
SAME_IP_OR_LOOPBACK,
// Match a connection originating from a different host.
EXTERNAL
}
/**
* Corresponds to Envoy proto message
* {@link io.envoyproxy.envoy.api.v2.listener.FilterChainMatch}.
@ -201,29 +219,62 @@ public final class EnvoyServerProtoData {
private final int destinationPort;
private final List<CidrRange> prefixRanges;
private final List<String> applicationProtocols;
private final List<CidrRange> sourcePrefixRanges;
private final ConnectionSourceType sourceType;
private final List<Integer> sourcePorts;
@VisibleForTesting
FilterChainMatch(int destinationPort,
List<CidrRange> prefixRanges, List<String> applicationProtocols) {
FilterChainMatch(
int destinationPort,
List<CidrRange> prefixRanges,
List<String> applicationProtocols,
List<CidrRange> sourcePrefixRanges,
ConnectionSourceType sourceType,
List<Integer> sourcePorts) {
this.destinationPort = destinationPort;
this.prefixRanges = Collections.unmodifiableList(prefixRanges);
this.applicationProtocols = Collections.unmodifiableList(applicationProtocols);
this.sourcePrefixRanges = sourcePrefixRanges;
this.sourceType = sourceType;
this.sourcePorts = sourcePorts;
}
static FilterChainMatch fromEnvoyProtoFilterChainMatch(
io.envoyproxy.envoy.config.listener.v3.FilterChainMatch proto) {
io.envoyproxy.envoy.config.listener.v3.FilterChainMatch proto)
throws InvalidProtocolBufferException {
List<CidrRange> prefixRanges = new ArrayList<>();
for (io.envoyproxy.envoy.config.core.v3.CidrRange range : proto.getPrefixRangesList()) {
prefixRanges.add(CidrRange.fromEnvoyProtoCidrRange(range));
}
List<CidrRange> sourcePrefixRanges = new ArrayList<>();
for (io.envoyproxy.envoy.config.core.v3.CidrRange range : proto.getSourcePrefixRangesList()) {
sourcePrefixRanges.add(CidrRange.fromEnvoyProtoCidrRange(range));
}
List<String> applicationProtocols = new ArrayList<>();
for (String appProtocol : proto.getApplicationProtocolsList()) {
for (String appProtocol : proto.getApplicationProtocolsList()) {
applicationProtocols.add(appProtocol);
}
ConnectionSourceType sourceType = null;
switch (proto.getSourceType()) {
case ANY:
sourceType = ConnectionSourceType.ANY;
break;
case EXTERNAL:
sourceType = ConnectionSourceType.EXTERNAL;
break;
case SAME_IP_OR_LOOPBACK:
sourceType = ConnectionSourceType.SAME_IP_OR_LOOPBACK;
break;
default:
throw new InvalidProtocolBufferException("Unknown source-type:" + proto.getSourceType());
}
return new FilterChainMatch(
proto.getDestinationPort().getValue(),
prefixRanges,
applicationProtocols);
applicationProtocols,
sourcePrefixRanges,
sourceType,
proto.getSourcePortsList());
}
public int getDestinationPort() {
@ -238,6 +289,18 @@ public final class EnvoyServerProtoData {
return applicationProtocols;
}
public List<CidrRange> getSourcePrefixRanges() {
return sourcePrefixRanges;
}
public ConnectionSourceType getConnectionSourceType() {
return sourceType;
}
public List<Integer> getSourcePorts() {
return sourcePorts;
}
@Override
public boolean equals(Object o) {
if (this == o) {
@ -248,22 +311,34 @@ public final class EnvoyServerProtoData {
}
FilterChainMatch that = (FilterChainMatch) o;
return destinationPort == that.destinationPort
&& java.util.Objects.equals(prefixRanges, that.prefixRanges)
&& java.util.Objects.equals(applicationProtocols, that.applicationProtocols);
&& Objects.equals(prefixRanges, that.prefixRanges)
&& Objects.equals(applicationProtocols, that.applicationProtocols)
&& Objects.equals(sourcePrefixRanges, that.sourcePrefixRanges)
&& sourceType == that.sourceType
&& Objects.equals(sourcePorts, that.sourcePorts);
}
@Override
public int hashCode() {
return java.util.Objects.hash(destinationPort, prefixRanges, applicationProtocols);
return Objects.hash(
destinationPort,
prefixRanges,
applicationProtocols,
sourcePrefixRanges,
sourceType,
sourcePorts);
}
@Override
public String toString() {
return "FilterChainMatch{"
+ "destinationPort=" + destinationPort
+ ", prefixRanges=" + prefixRanges
+ ", applicationProtocols=" + applicationProtocols
+ '}';
return MoreObjects.toStringHelper(this)
.add("destinationPort", destinationPort)
.add("prefixRanges", prefixRanges)
.add("applicationProtocols", applicationProtocols)
.add("sourcePrefixRanges", sourcePrefixRanges)
.add("sourceType", sourceType)
.add("sourcePorts", sourcePorts)
.toString();
}
}
@ -351,13 +426,15 @@ public final class EnvoyServerProtoData {
@Nullable
private final String address;
private final List<FilterChain> filterChains;
private final FilterChain defaultFilterChain;
@VisibleForTesting
Listener(String name, String address,
List<FilterChain> filterChains) {
List<FilterChain> filterChains, FilterChain defaultFilterChain) {
this.name = name;
this.address = address;
this.filterChains = Collections.unmodifiableList(filterChains);
this.defaultFilterChain = defaultFilterChain;
}
private static String convertEnvoyAddressToString(Address proto) {
@ -381,12 +458,33 @@ public final class EnvoyServerProtoData {
List<FilterChain> filterChains = new ArrayList<>(proto.getFilterChainsCount());
for (io.envoyproxy.envoy.config.listener.v3.FilterChain filterChain :
proto.getFilterChainsList()) {
filterChains.add(FilterChain.fromEnvoyProtoFilterChain(filterChain));
if (isAcceptable(filterChain.getFilterChainMatch())) {
filterChains.add(FilterChain.fromEnvoyProtoFilterChain(filterChain));
}
}
return new Listener(
proto.getName(),
convertEnvoyAddressToString(proto.getAddress()),
filterChains);
filterChains, FilterChain.fromEnvoyProtoFilterChain(proto.getDefaultFilterChain()));
}
// check if a filter is acceptable for gRPC server side processing
private static boolean isAcceptable(
io.envoyproxy.envoy.config.listener.v3.FilterChainMatch filterChainMatch) {
// reject if filer-chain-match
// - has server_name
// - transport protocol is other than "raw_buffer"
// - application_protocols is non-empty (for now accept "managed-mtls")
if (!filterChainMatch.getServerNamesList().isEmpty()) {
return false;
}
String transportProtocol = filterChainMatch.getTransportProtocol();
if (!transportProtocol.isEmpty() && !"raw_buffer".equals(transportProtocol)) {
return false;
}
List<String> appProtocols = filterChainMatch.getApplicationProtocolsList();
return appProtocols.isEmpty()
|| appProtocols.contains("managed-mtls"); // TODO(sanjaypujare): remove once TD fixed
}
public String getName() {
@ -401,6 +499,10 @@ public final class EnvoyServerProtoData {
return filterChains;
}
public FilterChain getDefaultFilterChain() {
return defaultFilterChain;
}
@Override
public boolean equals(Object o) {
if (this == o) {
@ -410,22 +512,30 @@ public final class EnvoyServerProtoData {
return false;
}
Listener listener = (Listener) o;
return java.util.Objects.equals(name, listener.name)
&& java.util.Objects.equals(address, listener.address)
&& java.util.Objects.equals(filterChains, listener.filterChains);
return Objects.equals(name, listener.name)
&& Objects.equals(address, listener.address)
&& Objects.equals(filterChains, listener.filterChains)
&& Objects.equals(defaultFilterChain, listener.defaultFilterChain);
}
@Override
public int hashCode() {
return java.util.Objects.hash(name, address, filterChains);
return Objects.hash(name, address, filterChains, defaultFilterChain);
}
@Override
public String toString() {
return "Listener{"
+ "name='" + name + '\''
+ ", address='" + address + '\''
+ ", filterChains=" + filterChains
+ "name='"
+ name
+ '\''
+ ", address='"
+ address
+ '\''
+ ", filterChains="
+ filterChains
+ ", defaultFilterChain="
+ defaultFilterChain
+ '}';
}
}

View File

@ -21,6 +21,7 @@ import static com.google.common.base.Preconditions.checkState;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.UInt32Value;
import io.grpc.Grpc;
import io.grpc.Internal;
import io.grpc.ManagedChannel;
@ -38,14 +39,16 @@ import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.util.concurrent.DefaultThreadFactory;
import java.io.IOException;
import java.math.BigInteger;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@ -170,31 +173,199 @@ public final class XdsClientWrapperForServerSds {
public DownstreamTlsContext getDownstreamTlsContext(Channel channel) {
if (curListener != null && channel != null) {
SocketAddress localAddress = channel.localAddress();
checkState(
localAddress instanceof InetSocketAddress,
"Channel localAddress is expected to be InetSocketAddress");
InetSocketAddress localInetAddr = (InetSocketAddress) localAddress;
checkState(
port == localInetAddr.getPort(),
"Channel localAddress port does not match requested listener port");
return getDownstreamTlsContext(localInetAddr);
SocketAddress remoteAddress = channel.remoteAddress();
if (localAddress instanceof InetSocketAddress && remoteAddress instanceof InetSocketAddress) {
InetSocketAddress localInetAddr = (InetSocketAddress) localAddress;
InetSocketAddress remoteInetAddr = (InetSocketAddress) remoteAddress;
checkState(
port == localInetAddr.getPort(),
"Channel localAddress port does not match requested listener port");
return getDownstreamTlsContext(localInetAddr, remoteInetAddr);
}
}
return null;
}
private DownstreamTlsContext getDownstreamTlsContext(InetSocketAddress localInetAddr) {
checkNotNull(localInetAddr, "localInetAddr");
if (curListener != null) {
List<FilterChain> filterChains = curListener.getFilterChains();
FilterChainComparator comparator = new FilterChainComparator(localInetAddr);
FilterChain bestMatch =
filterChains.isEmpty() ? null : Collections.max(filterChains, comparator);
if (bestMatch != null
&& (newServerApi || comparator.isMatching(bestMatch.getFilterChainMatch()))) {
return bestMatch.getDownstreamTlsContext();
/**
* Using the logic specified at
* https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/listener/listener_components.proto.html?highlight=filter%20chain#listener-filterchainmatch
* locate a matching filter and return the corresponding DownstreamTlsContext or else return one
* from default filter chain.
*
* @param localInetAddr dest address of the inbound connection
* @param remoteInetAddr source address of the inbound connection
*/
private DownstreamTlsContext getDownstreamTlsContext(
InetSocketAddress localInetAddr, InetSocketAddress remoteInetAddr) {
List<FilterChain> filterChains = curListener.getFilterChains();
filterChains = filterOnDestinationPort(filterChains);
filterChains = filterOnIpAddress(filterChains, localInetAddr.getAddress(), true);
filterChains =
filterOnSourceType(filterChains, remoteInetAddr.getAddress(), localInetAddr.getAddress());
filterChains = filterOnIpAddress(filterChains, remoteInetAddr.getAddress(), false);
filterChains = filterOnSourcePort(filterChains, remoteInetAddr.getPort());
// if we get more than 1, we ignore filterChains and use the defaultFilerChain
// although spec not clear for that case
if (filterChains.size() == 1) {
return filterChains.get(0).getDownstreamTlsContext();
}
return curListener.getDefaultFilterChain().getDownstreamTlsContext();
}
// destination_port present => Always fail match
private static List<FilterChain> filterOnDestinationPort(List<FilterChain> filterChains) {
ArrayList<FilterChain> filtered = new ArrayList<>(filterChains.size());
for (FilterChain filterChain : filterChains) {
FilterChainMatch filterChainMatch = filterChain.getFilterChainMatch();
if (filterChainMatch.getDestinationPort() == UInt32Value.getDefaultInstance().getValue()) {
filtered.add(filterChain);
}
}
return null;
return filtered;
}
private static List<FilterChain> filterOnSourcePort(
List<FilterChain> filterChains, int sourcePort) {
ArrayList<FilterChain> filteredOnMatch = new ArrayList<>(filterChains.size());
ArrayList<FilterChain> filteredOnEmpty = new ArrayList<>(filterChains.size());
for (FilterChain filterChain : filterChains) {
FilterChainMatch filterChainMatch = filterChain.getFilterChainMatch();
List<Integer> sourcePortsToMatch = filterChainMatch.getSourcePorts();
if (sourcePortsToMatch.isEmpty()) {
filteredOnEmpty.add(filterChain);
} else if (sourcePortsToMatch.contains(sourcePort)) {
filteredOnMatch.add(filterChain);
}
}
// match against source port is more specific than match against empty list
return filteredOnMatch.isEmpty() ? filteredOnEmpty : filteredOnMatch;
}
private List<FilterChain> filterOnSourceType(
List<FilterChain> filterChains, InetAddress sourceAddress, InetAddress destAddress) {
ArrayList<FilterChain> filtered = new ArrayList<>(filterChains.size());
for (FilterChain filterChain : filterChains) {
FilterChainMatch filterChainMatch = filterChain.getFilterChainMatch();
EnvoyServerProtoData.ConnectionSourceType sourceType =
filterChainMatch.getConnectionSourceType();
boolean matching = false;
if (sourceType == EnvoyServerProtoData.ConnectionSourceType.SAME_IP_OR_LOOPBACK) {
matching =
sourceAddress.isLoopbackAddress()
|| sourceAddress.isAnyLocalAddress()
|| sourceAddress.equals(destAddress);
} else if (sourceType == EnvoyServerProtoData.ConnectionSourceType.EXTERNAL) {
matching = !sourceAddress.isLoopbackAddress() && !sourceAddress.isAnyLocalAddress();
} else { // ANY or null
matching = true;
}
if (matching) {
filtered.add(filterChain);
}
}
return filtered;
}
private static boolean isCidrMatching(byte[] cidrBytes, byte[] addressBytes, int prefixLen) {
BigInteger cidrInt = new BigInteger(cidrBytes);
BigInteger addrInt = new BigInteger(addressBytes);
int shiftAmount = 8 * cidrBytes.length - prefixLen;
cidrInt = cidrInt.shiftRight(shiftAmount);
addrInt = addrInt.shiftRight(shiftAmount);
return cidrInt.equals(addrInt);
}
private static class QueueElement {
FilterChain filterChain;
int indexOfMatchingPrefixRange;
int matchingPrefixLength;
public QueueElement(FilterChain filterChain, InetAddress address, boolean forDestination) {
this.filterChain = filterChain;
FilterChainMatch filterChainMatch = filterChain.getFilterChainMatch();
byte[] addressBytes = address.getAddress();
boolean isIPv6 = address instanceof Inet6Address;
List<CidrRange> cidrRanges =
forDestination
? filterChainMatch.getPrefixRanges()
: filterChainMatch.getSourcePrefixRanges();
indexOfMatchingPrefixRange = -1;
if (cidrRanges.isEmpty()) { // if there is no CidrRange assume there is perfect match
matchingPrefixLength = isIPv6 ? 128 : 32;
} else {
matchingPrefixLength = 0;
int index = 0;
for (CidrRange cidrRange : cidrRanges) {
InetAddress cidrAddr = cidrRange.getAddressPrefix();
boolean cidrIsIpv6 = cidrAddr instanceof Inet6Address;
if (isIPv6 == cidrIsIpv6) {
byte[] cidrBytes = cidrAddr.getAddress();
int prefixLen = cidrRange.getPrefixLen();
if (isCidrMatching(cidrBytes, addressBytes, prefixLen)
&& prefixLen > matchingPrefixLength) {
matchingPrefixLength = prefixLen;
indexOfMatchingPrefixRange = index;
}
}
index++;
}
}
}
}
private static final class QueueElementComparator implements Comparator<QueueElement> {
@Override
public int compare(QueueElement o1, QueueElement o2) {
// descending order for max heap
return o2.matchingPrefixLength - o1.matchingPrefixLength;
}
@Override
public boolean equals(Object obj) {
return obj instanceof QueueElementComparator;
}
@Override
public int hashCode() {
return super.hashCode();
}
}
// use prefix_ranges (CIDR) and get the most specific matches
private List<FilterChain> filterOnIpAddress(
List<FilterChain> filterChains, InetAddress address, boolean forDestination) {
PriorityQueue<QueueElement> heap = new PriorityQueue<>(10, new QueueElementComparator());
for (FilterChain filterChain : filterChains) {
QueueElement element = new QueueElement(filterChain, address, forDestination);
if (element.matchingPrefixLength > 0) {
heap.add(element);
}
}
// get the top ones
ArrayList<FilterChain> topOnes = new ArrayList<>(heap.size());
int topMatchingPrefixLen = -1;
while (!heap.isEmpty()) {
QueueElement element = heap.remove();
if (topMatchingPrefixLen == -1) {
topMatchingPrefixLen = element.matchingPrefixLength;
} else {
if (element.matchingPrefixLength < topMatchingPrefixLen) {
break;
}
}
topOnes.add(element.filterChain);
}
return topOnes;
}
/** Adds a {@link ServerWatcher} to the list. */
@ -204,7 +375,7 @@ public final class XdsClientWrapperForServerSds {
serverWatchers.add(serverWatcher);
}
if (curListener != null) {
serverWatcher.onSuccess(getDownstreamTlsContext(new InetSocketAddress(port)));
serverWatcher.onSuccess();
}
}
@ -229,10 +400,8 @@ public final class XdsClientWrapperForServerSds {
}
private void reportSuccess() {
DownstreamTlsContext downstreamTlsContext =
getDownstreamTlsContext(new InetSocketAddress(port));
for (ServerWatcher watcher : getServerWatchers()) {
watcher.onSuccess(downstreamTlsContext);
watcher.onSuccess();
}
}
@ -249,97 +418,7 @@ public final class XdsClientWrapperForServerSds {
void onError(Throwable throwable);
/** Called to report successful receipt of server config. */
void onSuccess(DownstreamTlsContext downstreamTlsContext);
}
private static final class FilterChainComparator implements Comparator<FilterChain> {
private final InetSocketAddress localAddress;
private enum Match {
NO_MATCH,
EMPTY_PREFIX_RANGE_MATCH,
IPANY_MATCH,
EXACT_ADDRESS_MATCH
}
private FilterChainComparator(InetSocketAddress localAddress) {
checkNotNull(localAddress, "localAddress cannot be null");
this.localAddress = localAddress;
}
@Override
public int compare(FilterChain first, FilterChain second) {
checkNotNull(first, "first arg cannot be null");
checkNotNull(second, "second arg cannot be null");
FilterChainMatch firstMatch = first.getFilterChainMatch();
FilterChainMatch secondMatch = second.getFilterChainMatch();
if (firstMatch == null) {
return (secondMatch == null) ? 0 : (isMatching(secondMatch) ? -1 : 1);
} else {
return (secondMatch == null)
? (isMatching(firstMatch) ? 1 : -1)
: compare(firstMatch, secondMatch);
}
}
private int compare(FilterChainMatch first, FilterChainMatch second) {
int channelPort = localAddress.getPort();
if (first.getDestinationPort() == channelPort) {
return (second.getDestinationPort() == channelPort)
? compare(first.getPrefixRanges(), second.getPrefixRanges())
: (isInetAddressMatching(first.getPrefixRanges()) ? 1 : 0);
} else {
return (second.getDestinationPort() == channelPort)
? (isInetAddressMatching(second.getPrefixRanges()) ? -1 : 0)
: 0;
}
}
private int compare(List<CidrRange> first, List<CidrRange> second) {
return getInetAddressMatch(first).ordinal() - getInetAddressMatch(second).ordinal();
}
private boolean isInetAddressMatching(List<CidrRange> prefixRanges) {
return getInetAddressMatch(prefixRanges).ordinal() > Match.NO_MATCH.ordinal();
}
private Match getInetAddressMatch(List<CidrRange> prefixRanges) {
if (prefixRanges == null || prefixRanges.isEmpty()) {
return Match.EMPTY_PREFIX_RANGE_MATCH;
}
InetAddress localInetAddress = localAddress.getAddress();
for (CidrRange cidrRange : prefixRanges) {
if (cidrRange.getPrefixLen() == 32) {
try {
InetAddress cidrAddr = InetAddress.getByName(cidrRange.getAddressPrefix());
if (cidrAddr.isAnyLocalAddress()) {
return Match.IPANY_MATCH;
}
if (cidrAddr.equals(localInetAddress)) {
return Match.EXACT_ADDRESS_MATCH;
}
} catch (UnknownHostException e) {
logger.log(Level.WARNING, "cidrRange address parsing", e);
// continue
}
}
// TODO(sanjaypujare): implement prefix match logic as needed
}
return Match.NO_MATCH;
}
private boolean isMatching(FilterChainMatch filterChainMatch) {
if (filterChainMatch == null) {
return true;
}
int destPort = filterChainMatch.getDestinationPort();
if (destPort != localAddress.getPort()) {
return false;
}
return isInetAddressMatching(filterChainMatch.getPrefixRanges());
}
void onSuccess();
}
/** Shutdown this instance and release resources. */

View File

@ -92,8 +92,8 @@ public final class ServerWrapperForXds extends Server {
}
@Override
public void onSuccess(EnvoyServerProtoData.DownstreamTlsContext downstreamTlsContext) {
settableFuture.set(downstreamTlsContext);
public void onSuccess() {
settableFuture.set(null);
}
};
xdsClientWrapperForServerSds.addServerWatcher(serverWatcher);

View File

@ -57,6 +57,7 @@ public class EnvoyServerProtoDataTest {
.setAddress(address)
.addFilterChains(createOutFilter())
.addFilterChains(createInFilter())
.setDefaultFilterChain(createDefaultFilterChain())
.build();
Listener xdsListener = Listener.fromEnvoyProtoListener(listener);
@ -81,8 +82,13 @@ public class EnvoyServerProtoDataTest {
assertThat(inFilterChainMatch).isNotNull();
assertThat(inFilterChainMatch.getDestinationPort()).isEqualTo(8000);
assertThat(inFilterChainMatch.getApplicationProtocols()).containsExactly("managed-mtls");
assertThat(inFilterChainMatch.getPrefixRanges()).containsExactly(
new EnvoyServerProtoData.CidrRange("10.20.0.15", 32));
assertThat(inFilterChainMatch.getPrefixRanges())
.containsExactly(new EnvoyServerProtoData.CidrRange("10.20.0.15", 32));
assertThat(inFilterChainMatch.getSourcePrefixRanges())
.containsExactly(new EnvoyServerProtoData.CidrRange("10.30.3.0", 24));
assertThat(inFilterChainMatch.getConnectionSourceType())
.isEqualTo(EnvoyServerProtoData.ConnectionSourceType.EXTERNAL);
assertThat(inFilterChainMatch.getSourcePorts()).containsExactly(200, 300);
DownstreamTlsContext inFilterTlsContext = inFilter.getDownstreamTlsContext();
assertThat(inFilterTlsContext.getCommonTlsContext()).isNotNull();
CommonTlsContext commonTlsContext = inFilterTlsContext.getCommonTlsContext();
@ -90,6 +96,15 @@ public class EnvoyServerProtoDataTest {
.getTlsCertificateSdsSecretConfigsList();
assertThat(tlsCertSdsConfigs).hasSize(1);
assertThat(tlsCertSdsConfigs.get(0).getName()).isEqualTo("google-sds-config-default");
EnvoyServerProtoData.FilterChain defaultFilter = xdsListener.getDefaultFilterChain();
assertThat(defaultFilter).isNotNull();
EnvoyServerProtoData.FilterChainMatch defaultFilterChainMatch =
defaultFilter.getFilterChainMatch();
assertThat(defaultFilterChainMatch).isNotNull();
assertThat(defaultFilterChainMatch.getDestinationPort()).isEqualTo(8001);
assertThat(defaultFilterChainMatch.getPrefixRanges())
.containsExactly(new EnvoyServerProtoData.CidrRange("10.20.0.16", 30));
}
private static FilterChain createOutFilter() {
@ -116,7 +131,15 @@ public class EnvoyServerProtoDataTest {
.setAddressPrefix("10.20.0.15")
.setPrefixLen(UInt32Value.of(32))
.build())
.addSourcePrefixRanges(
CidrRange.newBuilder()
.setAddressPrefix("10.30.3.0")
.setPrefixLen(UInt32Value.of(24))
.build())
.addApplicationProtocols("managed-mtls")
.setSourceType(FilterChainMatch.ConnectionSourceType.EXTERNAL)
.addSourcePorts(200)
.addSourcePorts(300)
.build())
.setTransportSocket(TransportSocket.newBuilder().setName("envoy.transport_sockets.tls")
.setTypedConfig(
@ -133,4 +156,38 @@ public class EnvoyServerProtoDataTest {
.build();
return filterChain;
}
private static FilterChain createDefaultFilterChain() {
FilterChain filterChain =
FilterChain.newBuilder()
.setFilterChainMatch(
FilterChainMatch.newBuilder()
.setDestinationPort(UInt32Value.of(8001))
.addPrefixRanges(
CidrRange.newBuilder()
.setAddressPrefix("10.20.0.16")
.setPrefixLen(UInt32Value.of(30))
.build())
.build())
.setTransportSocket(
TransportSocket.newBuilder()
.setName("envoy.transport_sockets.tls")
.setTypedConfig(
Any.pack(
CommonTlsContextTestsUtil.buildTestDownstreamTlsContext(
"google-sds-config-default", "ROOTCA")))
.build())
.addFilters(
Filter.newBuilder()
.setName("envoy.http_connection_manager")
.setTypedConfig(
Any.newBuilder()
.setTypeUrl(
"type.googleapis.com/"
+ "envoy.config.filter.network.http_connection_manager"
+ ".v2.HttpConnectionManager"))
.build())
.build();
return filterChain;
}
}

View File

@ -0,0 +1,652 @@
/*
* Copyright 2021 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc.xds;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import com.google.protobuf.InvalidProtocolBufferException;
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
import io.netty.channel.Channel;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/** Tests for {@link XdsClientWrapperForServerSds}. */
@RunWith(JUnit4.class)
public class FilterChainMatchTest {
private static final int PORT = 7000;
private static final String LOCAL_IP = "10.1.2.3"; // dest
private static final String REMOTE_IP = "10.4.2.3"; // source
@Mock private XdsClient xdsClient;
@Mock private Channel channel;
private XdsClientWrapperForServerSds xdsClientWrapperForServerSds;
private XdsClient.ListenerWatcher registeredWatcher;
@Before
public void setUp() throws IOException {
MockitoAnnotations.initMocks(this);
xdsClientWrapperForServerSds = new XdsClientWrapperForServerSds(PORT);
registeredWatcher =
XdsServerTestHelper.startAndGetWatcher(xdsClientWrapperForServerSds, xdsClient, PORT);
}
@After
public void tearDown() {
xdsClientWrapperForServerSds.shutdown();
}
@Test
public void singleFilterChainWithoutAlpn() throws UnknownHostException {
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
EnvoyServerProtoData.FilterChainMatch filterChainMatch =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
DownstreamTlsContext tlsContext =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
EnvoyServerProtoData.FilterChain filterChain =
new EnvoyServerProtoData.FilterChain(filterChainMatch, tlsContext);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener("listener1", LOCAL_IP, Arrays.asList(filterChain), null);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContext1 =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContext1).isSameInstanceAs(tlsContext);
}
@Test
public void singleFilterChainWithAlpn() throws UnknownHostException {
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
EnvoyServerProtoData.FilterChainMatch filterChainMatch =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
Arrays.asList("managed-mtls"),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
DownstreamTlsContext tlsContext =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
EnvoyServerProtoData.FilterChain filterChain =
new EnvoyServerProtoData.FilterChain(filterChainMatch, tlsContext);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener("listener1", LOCAL_IP, Arrays.asList(filterChain), null);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContext1 =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContext1).isSameInstanceAs(tlsContext);
}
@Test
public void defaultFilterChain() throws UnknownHostException {
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
DownstreamTlsContext tlsContext =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
EnvoyServerProtoData.FilterChain filterChain =
new EnvoyServerProtoData.FilterChain(null, tlsContext);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(
"listener1", LOCAL_IP, Arrays.<EnvoyServerProtoData.FilterChain>asList(), filterChain);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContext1 =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContext1).isSameInstanceAs(tlsContext);
}
@Test
public void destPortFails_returnDefaultFilterChain() throws UnknownHostException {
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
DownstreamTlsContext tlsContextWithDestPort =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
EnvoyServerProtoData.FilterChainMatch filterChainMatchWithDestPort =
new EnvoyServerProtoData.FilterChainMatch(
PORT,
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
Arrays.asList("managed-mtls"),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainWithDestPort =
new EnvoyServerProtoData.FilterChain(filterChainMatchWithDestPort, tlsContextWithDestPort);
DownstreamTlsContext tlsContextForDefaultFilterChain =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
EnvoyServerProtoData.FilterChain defaultFilterChain =
new EnvoyServerProtoData.FilterChain(null, tlsContextForDefaultFilterChain);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(
"listener1", LOCAL_IP, Arrays.asList(filterChainWithDestPort), defaultFilterChain);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContext1 =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContext1).isSameInstanceAs(tlsContextForDefaultFilterChain);
}
@Test
public void destPrefixRangeMatch() throws UnknownHostException, InvalidProtocolBufferException {
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
DownstreamTlsContext tlsContextMatch =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMatch =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.asList(new EnvoyServerProtoData.CidrRange("10.1.2.0", 24)),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainWithMatch =
new EnvoyServerProtoData.FilterChain(filterChainMatchWithMatch, tlsContextMatch);
DownstreamTlsContext tlsContextForDefaultFilterChain =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
EnvoyServerProtoData.FilterChain defaultFilterChain =
new EnvoyServerProtoData.FilterChain(null, tlsContextForDefaultFilterChain);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(
"listener1", LOCAL_IP, Arrays.asList(filterChainWithMatch), defaultFilterChain);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContext1 =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContext1).isSameInstanceAs(tlsContextMatch);
}
@Test
public void destPrefixRangeMismatch_returnDefaultFilterChain()
throws UnknownHostException, InvalidProtocolBufferException {
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
DownstreamTlsContext tlsContextMismatch =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
// 10.2.2.0/24 doesn't match LOCAL_IP
EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMismatch =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.asList(new EnvoyServerProtoData.CidrRange("10.2.2.0", 24)),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainWithMismatch =
new EnvoyServerProtoData.FilterChain(filterChainMatchWithMismatch, tlsContextMismatch);
DownstreamTlsContext tlsContextForDefaultFilterChain =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
EnvoyServerProtoData.FilterChain defaultFilterChain =
new EnvoyServerProtoData.FilterChain(null, tlsContextForDefaultFilterChain);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(
"listener1", LOCAL_IP, Arrays.asList(filterChainWithMismatch), defaultFilterChain);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContext1 =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContext1).isSameInstanceAs(tlsContextForDefaultFilterChain);
}
@Test
public void destPrefixRange_moreSpecificWins()
throws UnknownHostException, InvalidProtocolBufferException {
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
DownstreamTlsContext tlsContextLessSpecific =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.asList(new EnvoyServerProtoData.CidrRange("10.1.2.0", 24)),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainLessSpecific =
new EnvoyServerProtoData.FilterChain(filterChainMatchLessSpecific, tlsContextLessSpecific);
DownstreamTlsContext tlsContextMoreSpecific =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecific =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.asList(new EnvoyServerProtoData.CidrRange("10.1.2.2", 31)),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainMoreSpecific =
new EnvoyServerProtoData.FilterChain(filterChainMatchMoreSpecific, tlsContextMoreSpecific);
EnvoyServerProtoData.FilterChain defaultFilterChain =
new EnvoyServerProtoData.FilterChain(null, null);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(
"listener1",
LOCAL_IP,
Arrays.asList(filterChainLessSpecific, filterChainMoreSpecific),
defaultFilterChain);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContext1 =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecific);
}
@Test
public void destPrefixRangeIpv6_moreSpecificWins()
throws UnknownHostException, InvalidProtocolBufferException {
setupChannel("FE80:0000:0000:0000:0202:B3FF:FE1E:8329", "2001:DB8::8:800:200C:417A", 15000);
DownstreamTlsContext tlsContextLessSpecific =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.asList(new EnvoyServerProtoData.CidrRange("FE80:0:0:0:0:0:0:0", 60)),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainLessSpecific =
new EnvoyServerProtoData.FilterChain(filterChainMatchLessSpecific, tlsContextLessSpecific);
DownstreamTlsContext tlsContextMoreSpecific =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecific =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.asList(new EnvoyServerProtoData.CidrRange("FE80:0000:0000:0000:0202:0:0:0", 80)),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainMoreSpecific =
new EnvoyServerProtoData.FilterChain(filterChainMatchMoreSpecific, tlsContextMoreSpecific);
EnvoyServerProtoData.FilterChain defaultFilterChain =
new EnvoyServerProtoData.FilterChain(null, null);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(
"listener1",
"FE80:0000:0000:0000:0202:B3FF:FE1E:8329",
Arrays.asList(filterChainLessSpecific, filterChainMoreSpecific),
defaultFilterChain);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContext1 =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecific);
}
@Test
public void destPrefixRange_moreSpecificWith2Wins()
throws UnknownHostException, InvalidProtocolBufferException {
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
DownstreamTlsContext tlsContextMoreSpecificWith2 =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecificWith2 =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.asList(
new EnvoyServerProtoData.CidrRange("10.1.2.0", 24),
new EnvoyServerProtoData.CidrRange(LOCAL_IP, 32)),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainMoreSpecificWith2 =
new EnvoyServerProtoData.FilterChain(
filterChainMatchMoreSpecificWith2, tlsContextMoreSpecificWith2);
DownstreamTlsContext tlsContextLessSpecific =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.asList(new EnvoyServerProtoData.CidrRange("10.1.2.2", 31)),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainLessSpecific =
new EnvoyServerProtoData.FilterChain(filterChainMatchLessSpecific, tlsContextLessSpecific);
EnvoyServerProtoData.FilterChain defaultFilterChain =
new EnvoyServerProtoData.FilterChain(null, null);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(
"listener1",
LOCAL_IP,
Arrays.asList(filterChainMoreSpecificWith2, filterChainLessSpecific),
defaultFilterChain);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContext1 =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecificWith2);
}
@Test
public void sourceTypeMismatch_returnDefaultFilterChain() throws UnknownHostException {
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
DownstreamTlsContext tlsContextMismatch =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMismatch =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.SAME_IP_OR_LOOPBACK,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainWithMismatch =
new EnvoyServerProtoData.FilterChain(filterChainMatchWithMismatch, tlsContextMismatch);
DownstreamTlsContext tlsContextForDefaultFilterChain =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
EnvoyServerProtoData.FilterChain defaultFilterChain =
new EnvoyServerProtoData.FilterChain(null, tlsContextForDefaultFilterChain);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(
"listener1", LOCAL_IP, Arrays.asList(filterChainWithMismatch), defaultFilterChain);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContext1 =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContext1).isSameInstanceAs(tlsContextForDefaultFilterChain);
}
@Test
public void sourceTypeLocal() throws UnknownHostException {
setupChannel(LOCAL_IP, LOCAL_IP, 15000);
DownstreamTlsContext tlsContextMatch =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMatch =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.SAME_IP_OR_LOOPBACK,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainWithMatch =
new EnvoyServerProtoData.FilterChain(filterChainMatchWithMatch, tlsContextMatch);
DownstreamTlsContext tlsContextForDefaultFilterChain =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
EnvoyServerProtoData.FilterChain defaultFilterChain =
new EnvoyServerProtoData.FilterChain(null, tlsContextForDefaultFilterChain);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(
"listener1", LOCAL_IP, Arrays.asList(filterChainWithMatch), defaultFilterChain);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContext1 =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContext1).isSameInstanceAs(tlsContextMatch);
}
@Test
public void sourcePrefixRange_moreSpecificWith2Wins()
throws UnknownHostException, InvalidProtocolBufferException {
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
DownstreamTlsContext tlsContextMoreSpecificWith2 =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecificWith2 =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
Arrays.<String>asList(),
Arrays.asList(
new EnvoyServerProtoData.CidrRange("10.4.2.0", 24),
new EnvoyServerProtoData.CidrRange(REMOTE_IP, 32)),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainMoreSpecificWith2 =
new EnvoyServerProtoData.FilterChain(
filterChainMatchMoreSpecificWith2, tlsContextMoreSpecificWith2);
DownstreamTlsContext tlsContextLessSpecific =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
Arrays.<String>asList(),
Arrays.asList(new EnvoyServerProtoData.CidrRange("10.4.2.2", 31)),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainLessSpecific =
new EnvoyServerProtoData.FilterChain(filterChainMatchLessSpecific, tlsContextLessSpecific);
EnvoyServerProtoData.FilterChain defaultFilterChain =
new EnvoyServerProtoData.FilterChain(null, null);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(
"listener1",
LOCAL_IP,
Arrays.asList(filterChainMoreSpecificWith2, filterChainLessSpecific),
defaultFilterChain);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContext1 =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecificWith2);
}
@Test
public void sourcePortMatch_exactMatchWinsOverEmptyList()
throws UnknownHostException, InvalidProtocolBufferException {
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
DownstreamTlsContext tlsContextEmptySourcePorts =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
EnvoyServerProtoData.FilterChainMatch filterChainMatchEmptySourcePorts =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
Arrays.<String>asList(),
Arrays.asList(
new EnvoyServerProtoData.CidrRange("10.4.2.0", 24),
new EnvoyServerProtoData.CidrRange("10.4.2.2", 31)),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChainEmptySourcePorts =
new EnvoyServerProtoData.FilterChain(
filterChainMatchEmptySourcePorts, tlsContextEmptySourcePorts);
DownstreamTlsContext tlsContextSourcePortMatch =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
EnvoyServerProtoData.FilterChainMatch filterChainMatchSourcePortMatch =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
Arrays.<String>asList(),
Arrays.asList(new EnvoyServerProtoData.CidrRange("10.4.2.2", 31)),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.asList(7000, 15000));
EnvoyServerProtoData.FilterChain filterChainSourcePortMatch =
new EnvoyServerProtoData.FilterChain(
filterChainMatchSourcePortMatch, tlsContextSourcePortMatch);
EnvoyServerProtoData.FilterChain defaultFilterChain =
new EnvoyServerProtoData.FilterChain(null, null);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(
"listener1",
LOCAL_IP,
Arrays.asList(filterChainEmptySourcePorts, filterChainSourcePortMatch),
defaultFilterChain);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContext1 =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContext1).isSameInstanceAs(tlsContextSourcePortMatch);
}
/**
* Create 6 filterChains: - 1st filter chain has dest port & specific prefix range but is
* eliminated due to dest port - 5 advance to next step: 1 is eliminated due to being less
* specific than the remaining 4. - 4 advance to 3rd step: source type external eliminates one
* with local source_type. - 3 advance to 4th step: more specific 2 get picked based on
* source-prefix range. - 5th step: out of 2 one with matching source port gets picked
*/
@Test
public void filterChain_5stepMatch() throws UnknownHostException, InvalidProtocolBufferException {
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
DownstreamTlsContext tlsContext1 =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
DownstreamTlsContext tlsContext2 =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
DownstreamTlsContext tlsContext3 =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT3", "VA3");
DownstreamTlsContext tlsContext4 =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT4", "VA4");
DownstreamTlsContext tlsContext5 =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT5", "VA5");
DownstreamTlsContext tlsContext6 =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT6", "VA6");
// has dest port and specific prefix ranges: gets eliminated in step 1
EnvoyServerProtoData.FilterChainMatch filterChainMatch1 =
new EnvoyServerProtoData.FilterChainMatch(
PORT,
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
Arrays.<String>asList(),
Arrays.asList(new EnvoyServerProtoData.CidrRange(REMOTE_IP, 32)),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChain1 =
new EnvoyServerProtoData.FilterChain(filterChainMatch1, tlsContext1);
// next 5 use prefix range: 4 with prefixLen of 30 and last one with 29
// has single prefix range: and less specific source prefix range: gets eliminated in step 4
EnvoyServerProtoData.FilterChainMatch filterChainMatch2 =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.asList(new EnvoyServerProtoData.CidrRange("10.1.2.0", 30)),
Arrays.<String>asList(),
Arrays.asList(new EnvoyServerProtoData.CidrRange("10.4.0.0", 16)),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChain2 =
new EnvoyServerProtoData.FilterChain(filterChainMatch2, tlsContext2);
// has prefix ranges with one not matching and source type local: gets eliminated in step 3
EnvoyServerProtoData.FilterChainMatch filterChainMatch3 =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.asList(
new EnvoyServerProtoData.CidrRange("192.168.2.0", 24),
new EnvoyServerProtoData.CidrRange("10.1.2.0", 30)),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.SAME_IP_OR_LOOPBACK,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChain3 =
new EnvoyServerProtoData.FilterChain(filterChainMatch3, tlsContext3);
// has prefix ranges with both matching and source type external but non matching source port:
// gets eliminated in step 5
EnvoyServerProtoData.FilterChainMatch filterChainMatch4 =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.asList(
new EnvoyServerProtoData.CidrRange("10.1.0.0", 16),
new EnvoyServerProtoData.CidrRange("10.1.2.0", 30)),
Arrays.<String>asList(),
Arrays.asList(new EnvoyServerProtoData.CidrRange("10.4.2.0", 24)),
EnvoyServerProtoData.ConnectionSourceType.EXTERNAL,
Arrays.asList(16000, 9000));
EnvoyServerProtoData.FilterChain filterChain4 =
new EnvoyServerProtoData.FilterChain(filterChainMatch4, tlsContext4);
// has prefix ranges with both matching and source type external and matching source port: this
// gets selected
EnvoyServerProtoData.FilterChainMatch filterChainMatch5 =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.asList(
new EnvoyServerProtoData.CidrRange("10.1.0.0", 16),
new EnvoyServerProtoData.CidrRange("10.1.2.0", 30)),
Arrays.<String>asList(),
Arrays.asList(
new EnvoyServerProtoData.CidrRange("10.4.2.0", 24),
new EnvoyServerProtoData.CidrRange("192.168.2.0", 24)),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.asList(15000, 8000));
EnvoyServerProtoData.FilterChain filterChain5 =
new EnvoyServerProtoData.FilterChain(filterChainMatch5, tlsContext5);
// has prefix range with prefixLen of 29: gets eliminated in step 2
EnvoyServerProtoData.FilterChainMatch filterChainMatch6 =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.asList(new EnvoyServerProtoData.CidrRange("10.1.2.0", 29)),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
EnvoyServerProtoData.ConnectionSourceType.ANY,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChain6 =
new EnvoyServerProtoData.FilterChain(filterChainMatch6, tlsContext6);
EnvoyServerProtoData.FilterChain defaultFilterChain =
new EnvoyServerProtoData.FilterChain(null, null);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(
"listener1",
LOCAL_IP,
Arrays.asList(
filterChain1, filterChain2, filterChain3, filterChain4, filterChain5, filterChain6),
defaultFilterChain);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext tlsContextPicked =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(tlsContextPicked).isSameInstanceAs(tlsContext5);
}
private void setupChannel(String localIp, String remoteIp, int remotePort)
throws UnknownHostException {
when(channel.localAddress())
.thenReturn(new InetSocketAddress(InetAddress.getByName(localIp), PORT));
when(channel.remoteAddress())
.thenReturn(new InetSocketAddress(InetAddress.getByName(remoteIp), remotePort));
}
}

View File

@ -348,6 +348,88 @@ public class ServerXdsClientNewServerApiTest {
assertThat(fakeClock.getPendingTasks(LISTENER_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty();
}
@Test
public void ldsResponseWith_defaultFilterChainListener() throws InvalidProtocolBufferException {
xdsClient.watchListenerData(PORT, listenerWatcher);
StreamObserver<DiscoveryResponse> responseObserver = responseObservers.poll();
StreamObserver<DiscoveryRequest> requestObserver = requestObservers.poll();
verify(requestObserver)
.onNext(
eq(
XdsClientTestHelper.buildDiscoveryRequest(
NODE,
"",
ImmutableList.of("test/value?udpa.resource.listening_address=192.168.3.7:7000"),
ResourceType.LDS.typeUrl(),
"")));
assertThat(fakeClock.getPendingTasks(LISTENER_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).hasSize(1);
final FilterChain defaultFilterChain =
buildFilterChain(
buildFilterChainMatch("managed-mtls"),
CommonTlsContextTestsUtil.buildTestDownstreamTlsContext(
"google-sds-config-default", "ROOTCA"),
buildTestFilter("envoy.http_connection_manager"));
List<Any> listeners =
ImmutableList.of(
Any.pack(
buildListener(
"bar.googleapis.com",
Any.pack(
HttpConnectionManager.newBuilder()
.setRouteConfig(
buildRouteConfiguration(
"route-bar.googleapis.com",
ImmutableList.of(
buildVirtualHost(
ImmutableList.of("bar.googleapis.com"),
"cluster-bar.googleapis.com"))))
.build()))),
Any.pack(
buildListenerWithDefaultFilterChain(
"test/value?udpa.resource.listening_address=192.168.3.7:7000",
7000,
"0.0.0.0",
defaultFilterChain)));
DiscoveryResponse response =
buildDiscoveryResponse("0", listeners, ResourceType.LDS.typeUrl(), "0000");
responseObserver.onNext(response);
// Client sends an ACK LDS request.
verify(requestObserver)
.onNext(
eq(
XdsClientTestHelper.buildDiscoveryRequest(
NODE,
"0",
ImmutableList.of("test/value?udpa.resource.listening_address=192.168.3.7:7000"),
ResourceType.LDS.typeUrl(),
"0000")));
ArgumentCaptor<ListenerUpdate> listenerUpdateCaptor = ArgumentCaptor.forClass(null);
verify(listenerWatcher, times(1)).onListenerChanged(listenerUpdateCaptor.capture());
ListenerUpdate configUpdate = listenerUpdateCaptor.getValue();
EnvoyServerProtoData.Listener listener = configUpdate.getListener();
assertThat(listener.getName())
.isEqualTo("test/value?udpa.resource.listening_address=192.168.3.7:7000");
assertThat(listener.getAddress()).isEqualTo("0.0.0.0:7000");
assertThat(listener.getFilterChains()).hasSize(0);
EnvoyServerProtoData.FilterChain filterChainInboundInListenerUpdate =
listener.getDefaultFilterChain();
CommonTlsContext downstreamCommonTlsContext =
filterChainInboundInListenerUpdate.getDownstreamTlsContext().getCommonTlsContext();
assertThat(downstreamCommonTlsContext.getTlsCertificateSdsSecretConfigs(0).getName())
.isEqualTo("google-sds-config-default");
assertThat(
downstreamCommonTlsContext
.getCombinedValidationContext()
.getValidationContextSdsSecretConfig()
.getName())
.isEqualTo("ROOTCA");
assertThat(fakeClock.getPendingTasks(LISTENER_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty();
}
/** Client receives LDS responses for updating Listener previously received. */
@SuppressWarnings("unchecked")
@Test
@ -622,6 +704,25 @@ public class ServerXdsClientNewServerApiTest {
backoffPolicy2, requestObserver);
}
static Listener buildListenerWithDefaultFilterChain(String name, int portValue, String address,
FilterChain defaultFilterChain) {
io.envoyproxy.envoy.config.core.v3.Address listenerAddress =
io.envoyproxy.envoy.config.core.v3.Address.newBuilder()
.setSocketAddress(
SocketAddress.newBuilder().setPortValue(portValue).setAddress(address))
.build();
if (defaultFilterChain == null) {
defaultFilterChain = FilterChain.getDefaultInstance();
}
return
Listener.newBuilder()
.setName(name)
.setAddress(listenerAddress)
.setDefaultFilterChain(defaultFilterChain)
.setTrafficDirection(TrafficDirection.INBOUND)
.build();
}
static Listener buildListenerWithFilterChain(String name, int portValue, String address,
FilterChain... filterChains) {
io.envoyproxy.envoy.config.core.v3.Address listenerAddress =
@ -633,6 +734,7 @@ public class ServerXdsClientNewServerApiTest {
Listener.newBuilder()
.setName(name)
.setAddress(listenerAddress)
.setDefaultFilterChain(FilterChain.getDefaultInstance())
.addAllFilterChains(Arrays.asList(filterChains))
.setTrafficDirection(TrafficDirection.INBOUND)
.build();

View File

@ -1,213 +0,0 @@
/*
* Copyright 2020 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc.xds;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
import io.netty.channel.Channel;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/** Tests for {@link XdsClientWrapperForServerSds}. */
@RunWith(Parameterized.class)
public class XdsClientWrapperForServerSdsTest {
private static final int PORT = 7000;
/** Iterable of various configurations to use for tests. */
@Parameterized.Parameters(name = "{6}")
public static Iterable<Object[]> data() {
return Arrays.asList(
new Object[][] {
{
-1, // creates null filterChainMatch for filter1
null,
null,
"192.168.10.1",
"192.168.10.2",
1,
"null filter chain match, expect filter1"
},
{
PORT + 1,
"192.168.10.1",
"192.168.10.2",
null,
null,
2,
"only dest port match, expect filter2"
},
{
PORT, // matches dest port
"168.20.20.2",
"10.1.2.3", // matches local address
"192.168.10.1",
"192.168.10.2",
1,
"dest port & address match, expect filter1"
},
{
-1, // creates null filterChainMatch for filter1
null,
null,
null, // empty address range for filter2
null, // empty address range for filter2
2,
"empty address range over empty filterChainMatch, expect filter2"
},
{
PORT,
null,
null,
"192.168.1.4",
"0.0.0.0", // IPANY for filter2
2,
"IPANY over empty address match, expect filter2"
},
{
PORT,
"192.168.1.4",
"0.0.0.0", // IPANY for filter1
"168.154.4.7",
"10.1.2.3", // matches local address
2,
"exact IP over IPANY match, expect filter2"
},
{
PORT, // matches dest port but no address match
"168.20.20.2",
"10.1.2.4",
"192.168.10.1",
"192.168.10.2",
0,
"dest port match but no address match, expect null"
}
});
}
@Parameter(0)
public int destPort1;
@Parameter(1)
public String addressPrefix11;
@Parameter(2)
public String addressPrefix12;
@Parameter(3)
public String addressPrefix21;
@Parameter(4)
public String addressPrefix22;
@Parameter(5)
public int expectedIndex;
@Parameter(6)
public String testName;
@Mock private XdsClient xdsClient;
@Mock private Channel channel;
private XdsClientWrapperForServerSds xdsClientWrapperForServerSds;
private final DownstreamTlsContext[] tlsContexts = new DownstreamTlsContext[3];
/** Creates XdsClientWrapperForServerSds: also used by other classes. */
public static XdsClientWrapperForServerSds createXdsClientWrapperForServerSds(
int port, DownstreamTlsContext downstreamTlsContext) {
XdsClient mockXdsClient = mock(XdsClient.class);
XdsClientWrapperForServerSds xdsClientWrapperForServerSds =
new XdsClientWrapperForServerSds(port);
xdsClientWrapperForServerSds.start(mockXdsClient);
generateListenerUpdateToWatcher(
port, downstreamTlsContext, xdsClientWrapperForServerSds.getListenerWatcher());
return xdsClientWrapperForServerSds;
}
static void generateListenerUpdateToWatcher(
int port, DownstreamTlsContext tlsContext, XdsClient.ListenerWatcher registeredWatcher) {
EnvoyServerProtoData.Listener listener =
XdsSdsClientServerTest.buildListener("listener1", "0.0.0.0", port, tlsContext);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
}
@Before
public void setUp() throws IOException {
MockitoAnnotations.initMocks(this);
xdsClientWrapperForServerSds = new XdsClientWrapperForServerSds(PORT);
xdsClientWrapperForServerSds.start(xdsClient);
tlsContexts[0] = null;
tlsContexts[1] =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
tlsContexts[2] =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
}
@After
public void tearDown() {
xdsClientWrapperForServerSds.shutdown();
}
/**
* Common method called by most tests. Creates 2 filterChains each with 2 addresses. First
* filterChain's destPort is always PORT.
*/
@Test
public void commonFilterChainMatchTest()
throws UnknownHostException {
ArgumentCaptor<XdsClient.ListenerWatcher> listenerWatcherCaptor = ArgumentCaptor.forClass(null);
verify(xdsClient).watchListenerData(eq(PORT), listenerWatcherCaptor.capture());
XdsClient.ListenerWatcher registeredWatcher = listenerWatcherCaptor.getValue();
InetAddress ipLocalAddress = Inet4Address.getByName("10.1.2.3");
InetSocketAddress localAddress = new InetSocketAddress(ipLocalAddress, PORT);
when(channel.localAddress()).thenReturn(localAddress);
EnvoyServerProtoData.Listener listener =
XdsServerTestHelper.buildTestListener(
"listener1",
"10.1.2.3",
destPort1,
PORT,
addressPrefix11,
addressPrefix12,
addressPrefix21,
addressPrefix22,
tlsContexts[1],
tlsContexts[2]);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
DownstreamTlsContext downstreamTlsContext =
xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
assertThat(downstreamTlsContext).isSameInstanceAs(tlsContexts[expectedIndex]);
}
}

View File

@ -23,7 +23,6 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.same;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ -79,28 +78,20 @@ public class XdsClientWrapperForServerSdsTestMisc {
}
@Test
public void nonInetSocketAddress_expectException() {
public void nonInetSocketAddress_expectNull() throws UnknownHostException {
registeredWatcher =
XdsServerTestHelper.startAndGetWatcher(xdsClientWrapperForServerSds, xdsClient, PORT);
try {
DownstreamTlsContext unused =
sendListenerUpdate(new InProcessSocketAddress("test1"), null, null);
fail("exception expected");
} catch (IllegalStateException expected) {
assertThat(expected)
.hasMessageThat()
.isEqualTo("Channel localAddress is expected to be InetSocketAddress");
}
XdsServerTestHelper.startAndGetWatcher(xdsClientWrapperForServerSds, xdsClient, PORT);
assertThat(sendListenerUpdate(new InProcessSocketAddress("test1"), null)).isNull();
}
@Test
public void nonMatchingPort_expectException() throws UnknownHostException {
registeredWatcher =
XdsServerTestHelper.startAndGetWatcher(xdsClientWrapperForServerSds, xdsClient, PORT);
XdsServerTestHelper.startAndGetWatcher(xdsClientWrapperForServerSds, xdsClient, PORT);
try {
InetAddress ipLocalAddress = InetAddress.getByName("10.1.2.3");
InetSocketAddress localAddress = new InetSocketAddress(ipLocalAddress, PORT + 1);
DownstreamTlsContext unused = sendListenerUpdate(localAddress, null, null);
DownstreamTlsContext unused = sendListenerUpdate(localAddress, null);
fail("exception expected");
} catch (IllegalStateException expected) {
assertThat(expected)
@ -121,7 +112,10 @@ public class XdsClientWrapperForServerSdsTestMisc {
when(channel.localAddress()).thenReturn(localAddress);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(
"listener1", "10.1.2.3", Collections.<EnvoyServerProtoData.FilterChain>emptyList());
"listener1",
"10.1.2.3",
Collections.<EnvoyServerProtoData.FilterChain>emptyList(),
null);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
@ -141,10 +135,10 @@ public class XdsClientWrapperForServerSdsTestMisc {
EnvoyServerProtoData.DownstreamTlsContext tlsContext =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
verify(mockServerWatcher, never())
.onSuccess(any(EnvoyServerProtoData.DownstreamTlsContext.class));
DownstreamTlsContext returnedTlsContext = sendListenerUpdate(localAddress, tlsContext, null);
.onSuccess();
DownstreamTlsContext returnedTlsContext = sendListenerUpdate(localAddress, tlsContext);
assertThat(returnedTlsContext).isSameInstanceAs(tlsContext);
verify(mockServerWatcher).onSuccess(same(tlsContext));
verify(mockServerWatcher).onSuccess();
xdsClientWrapperForServerSds.removeServerWatcher(mockServerWatcher);
}
@ -156,12 +150,12 @@ public class XdsClientWrapperForServerSdsTestMisc {
InetSocketAddress localAddress = new InetSocketAddress(ipLocalAddress, PORT);
EnvoyServerProtoData.DownstreamTlsContext tlsContext =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
DownstreamTlsContext returnedTlsContext = sendListenerUpdate(localAddress, tlsContext, null);
DownstreamTlsContext returnedTlsContext = sendListenerUpdate(localAddress, tlsContext);
assertThat(returnedTlsContext).isSameInstanceAs(tlsContext);
XdsClientWrapperForServerSds.ServerWatcher mockServerWatcher =
mock(XdsClientWrapperForServerSds.ServerWatcher.class);
xdsClientWrapperForServerSds.addServerWatcher(mockServerWatcher);
verify(mockServerWatcher).onSuccess(same(tlsContext));
verify(mockServerWatcher).onSuccess();
}
@Test
@ -192,10 +186,10 @@ public class XdsClientWrapperForServerSdsTestMisc {
EnvoyServerProtoData.DownstreamTlsContext tlsContext =
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
verify(mockServerWatcher, never())
.onSuccess(any(EnvoyServerProtoData.DownstreamTlsContext.class));
DownstreamTlsContext returnedTlsContext = sendListenerUpdate(localAddress, tlsContext, null);
.onSuccess();
DownstreamTlsContext returnedTlsContext = sendListenerUpdate(localAddress, tlsContext);
assertThat(returnedTlsContext).isSameInstanceAs(tlsContext);
verify(mockServerWatcher).onSuccess(same(tlsContext));
verify(mockServerWatcher).onSuccess();
}
@Test
@ -215,12 +209,24 @@ public class XdsClientWrapperForServerSdsTestMisc {
}
private DownstreamTlsContext sendListenerUpdate(
SocketAddress localAddress,
DownstreamTlsContext tlsContext1,
DownstreamTlsContext tlsContext2) {
SocketAddress localAddress, DownstreamTlsContext tlsContext) throws UnknownHostException {
when(channel.localAddress()).thenReturn(localAddress);
XdsServerTestHelper.generateListenerUpdate(
registeredWatcher, PORT, tlsContext1, tlsContext2);
InetAddress ipRemoteAddress = InetAddress.getByName("10.4.5.6");
InetSocketAddress remoteAddress = new InetSocketAddress(ipRemoteAddress, 1234);
when(channel.remoteAddress()).thenReturn(remoteAddress);
XdsServerTestHelper.generateListenerUpdate(registeredWatcher, tlsContext);
return xdsClientWrapperForServerSds.getDownstreamTlsContext(channel);
}
/** Creates XdsClientWrapperForServerSds: also used by other classes. */
public static XdsClientWrapperForServerSds createXdsClientWrapperForServerSds(
int port, DownstreamTlsContext downstreamTlsContext) {
XdsClient mockXdsClient = mock(XdsClient.class);
XdsClientWrapperForServerSds xdsClientWrapperForServerSds =
new XdsClientWrapperForServerSds(port);
xdsClientWrapperForServerSds.start(mockXdsClient);
XdsSdsClientServerTest.generateListenerUpdateToWatcher(
downstreamTlsContext, xdsClientWrapperForServerSds.getListenerWatcher());
return xdsClientWrapperForServerSds;
}
}

View File

@ -17,7 +17,6 @@
package io.grpc.xds;
import static com.google.common.truth.Truth.assertThat;
import static io.grpc.xds.XdsServerTestHelper.buildFilterChainMatch;
import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.BAD_CLIENT_KEY_FILE;
import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.BAD_CLIENT_PEM_FILE;
import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.BAD_SERVER_KEY_FILE;
@ -293,8 +292,7 @@ public class XdsSdsClientServerTest {
DownstreamTlsContext downstreamTlsContext =
CommonTlsContextTestsUtil.buildDownstreamTlsContextFromFilenames(
BAD_SERVER_KEY_FILE, BAD_SERVER_PEM_FILE, CA_PEM_FILE);
XdsClientWrapperForServerSdsTest.generateListenerUpdateToWatcher(
port, downstreamTlsContext, listenerWatcher);
generateListenerUpdateToWatcher(downstreamTlsContext, listenerWatcher);
try {
SimpleServiceGrpc.SimpleServiceBlockingStub blockingStub =
getBlockingStub(upstreamTlsContext, "foo.test.google.fr");
@ -314,8 +312,7 @@ public class XdsSdsClientServerTest {
SERVER_1_KEY_FILE, SERVER_1_PEM_FILE, CA_PEM_FILE);
final XdsClientWrapperForServerSds xdsClientWrapperForServerSds =
XdsClientWrapperForServerSdsTest.createXdsClientWrapperForServerSds(
port, /* downstreamTlsContext= */ downstreamTlsContext);
createXdsClientWrapperForServerSds(port);
buildServerWithFallbackServerCredentials(
xdsClientWrapperForServerSds, InsecureServerCredentials.create(), downstreamTlsContext);
@ -353,6 +350,23 @@ public class XdsSdsClientServerTest {
buildServer(port, xdsCredentials, xdsClientWrapperForServerSds, downstreamTlsContext);
}
/** Creates XdsClientWrapperForServerSds. */
private static XdsClientWrapperForServerSds createXdsClientWrapperForServerSds(int port) {
XdsClient mockXdsClient = mock(XdsClient.class);
XdsClientWrapperForServerSds xdsClientWrapperForServerSds =
new XdsClientWrapperForServerSds(port);
xdsClientWrapperForServerSds.start(mockXdsClient);
return xdsClientWrapperForServerSds;
}
static void generateListenerUpdateToWatcher(
DownstreamTlsContext tlsContext, XdsClient.ListenerWatcher registeredWatcher) {
EnvoyServerProtoData.Listener listener = buildListener("listener1", "0.0.0.0", tlsContext);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
}
private void buildServer(
int port,
ServerCredentials serverCredentials,
@ -362,20 +376,24 @@ public class XdsSdsClientServerTest {
XdsServerBuilder builder = XdsServerBuilder.forPort(port, serverCredentials)
.addService(new SimpleServiceImpl());
XdsServerTestHelper.generateListenerUpdate(
xdsClientWrapperForServerSds.getListenerWatcher(),
port,
downstreamTlsContext,
/* tlsContext2= */null);
xdsClientWrapperForServerSds.getListenerWatcher(), downstreamTlsContext);
cleanupRule.register(builder.buildServer(xdsClientWrapperForServerSds)).start();
}
static EnvoyServerProtoData.Listener buildListener(
String name, String address, int port, DownstreamTlsContext tlsContext) {
EnvoyServerProtoData.FilterChainMatch filterChainMatch = buildFilterChainMatch(port, address);
EnvoyServerProtoData.FilterChain filterChain1 =
String name, String address, DownstreamTlsContext tlsContext) {
EnvoyServerProtoData.FilterChainMatch filterChainMatch =
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
null,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain defaultFilterChain =
new EnvoyServerProtoData.FilterChain(filterChainMatch, tlsContext);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(name, address, Arrays.asList(filterChain1));
new EnvoyServerProtoData.Listener(name, address, Arrays.asList(defaultFilterChain), null);
return listener;
}

View File

@ -144,9 +144,8 @@ public class XdsServerBuilderTest {
Future<Throwable> future = startServerAsync();
XdsServerTestHelper.generateListenerUpdate(
listenerWatcher,
port,
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
null);
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1")
);
verifyServer(future, null, null);
verifyShutdown();
}
@ -157,9 +156,8 @@ public class XdsServerBuilderTest {
buildServer(null, true);
XdsServerTestHelper.generateListenerUpdate(
listenerWatcher,
port,
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
null);
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1")
);
xdsServer.start();
try {
xdsServer.start();
@ -180,9 +178,8 @@ public class XdsServerBuilderTest {
Future<Throwable> future = startServerAsync();
XdsServerTestHelper.generateListenerUpdate(
listenerWatcher,
port,
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
null);
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1")
);
verifyServer(future, mockXdsServingStatusListener, null);
verifyShutdown();
}
@ -217,9 +214,8 @@ public class XdsServerBuilderTest {
reset(mockXdsServingStatusListener);
XdsServerTestHelper.generateListenerUpdate(
listenerWatcher,
port,
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
null);
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1")
);
verifyServer(future, mockXdsServingStatusListener, null);
verifyShutdown();
}
@ -235,9 +231,8 @@ public class XdsServerBuilderTest {
ServerSocket serverSocket = new ServerSocket(port);
XdsServerTestHelper.generateListenerUpdate(
listenerWatcher,
port,
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
null);
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1")
);
Throwable exception = future.get(5, TimeUnit.SECONDS);
assertThat(exception).isInstanceOf(IOException.class);
assertThat(exception).hasMessageThat().contains("Failed to bind");
@ -269,14 +264,12 @@ public class XdsServerBuilderTest {
Future<Throwable> future = startServerAsync();
XdsServerTestHelper.generateListenerUpdate(
listenerWatcher,
port,
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
null);
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1")
);
XdsServerTestHelper.generateListenerUpdate(
listenerWatcher,
port,
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
null);
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1")
);
verify(mockXdsServingStatusListener, never()).onNotServing(any(Throwable.class));
verifyServer(future, mockXdsServingStatusListener, null);
listenerWatcher.onError(Status.ABORTED);

View File

@ -19,12 +19,9 @@ package io.grpc.xds;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import com.google.common.base.Strings;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.Arrays;
import org.mockito.ArgumentCaptor;
/**
@ -43,31 +40,17 @@ class XdsServerTestHelper {
}
/**
* Creates a {@link XdsClient.ListenerUpdate} with maximum of 2
* {@link io.grpc.xds.EnvoyServerProtoData.FilterChain} each one with a destination port and an
* optional {@link EnvoyServerProtoData.DownstreamTlsContext}.
* @param registeredWatcher the watcher on which to generate the update
* @param destPort if > 0 to create both the {@link EnvoyServerProtoData.FilterChain}
* @param tlsContext1 if non-null, used to populate the 1st filterChain
* @param tlsContext2 if non-null, used to populate the 2nd filterChain
* Creates a {@link XdsClient.ListenerUpdate} with {@link
* io.grpc.xds.EnvoyServerProtoData.FilterChain} with a destination port and an optional {@link
* EnvoyServerProtoData.DownstreamTlsContext}.
*
* @param registeredWatcher the watcher on which to generate the update
* @param tlsContext if non-null, used to populate filterChain
*/
static void generateListenerUpdate(
XdsClient.ListenerWatcher registeredWatcher,
int destPort,
EnvoyServerProtoData.DownstreamTlsContext tlsContext1,
EnvoyServerProtoData.DownstreamTlsContext tlsContext2) {
EnvoyServerProtoData.Listener listener =
buildTestListener(
"listener1",
"10.1.2.3",
destPort,
destPort,
null,
null,
null,
null,
tlsContext1,
tlsContext2);
XdsClient.ListenerWatcher registeredWatcher,
EnvoyServerProtoData.DownstreamTlsContext tlsContext) {
EnvoyServerProtoData.Listener listener = buildTestListener("listener1", "10.1.2.3", tlsContext);
XdsClient.ListenerUpdate listenerUpdate =
XdsClient.ListenerUpdate.newBuilder().setListener(listener).build();
registeredWatcher.onListenerChanged(listenerUpdate);
@ -81,38 +64,22 @@ class XdsServerTestHelper {
}
static EnvoyServerProtoData.Listener buildTestListener(
String name,
String address,
int destPort1,
int destPort2,
String addressPrefix11,
String addressPrefix12,
String addressPrefix21,
String addressPrefix22,
EnvoyServerProtoData.DownstreamTlsContext tlsContext1,
EnvoyServerProtoData.DownstreamTlsContext tlsContext2) {
String name, String address, EnvoyServerProtoData.DownstreamTlsContext tlsContext) {
EnvoyServerProtoData.FilterChainMatch filterChainMatch1 =
destPort1 > 0 ? buildFilterChainMatch(destPort1, addressPrefix11, addressPrefix12) : null;
EnvoyServerProtoData.FilterChainMatch filterChainMatch2 =
destPort2 > 0 ? buildFilterChainMatch(destPort2, addressPrefix21, addressPrefix22) : null;
new EnvoyServerProtoData.FilterChainMatch(
0,
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
Arrays.<String>asList(),
Arrays.<EnvoyServerProtoData.CidrRange>asList(),
null,
Arrays.<Integer>asList());
EnvoyServerProtoData.FilterChain filterChain1 =
new EnvoyServerProtoData.FilterChain(filterChainMatch1, tlsContext1);
EnvoyServerProtoData.FilterChain filterChain2 =
new EnvoyServerProtoData.FilterChain(filterChainMatch2, tlsContext2);
new EnvoyServerProtoData.FilterChain(filterChainMatch1, tlsContext);
EnvoyServerProtoData.FilterChain defaultFilterChain =
new EnvoyServerProtoData.FilterChain(null, null);
EnvoyServerProtoData.Listener listener =
new EnvoyServerProtoData.Listener(name, address, Arrays.asList(filterChain1, filterChain2));
new EnvoyServerProtoData.Listener(
name, address, Arrays.asList(filterChain1), defaultFilterChain);
return listener;
}
static EnvoyServerProtoData.FilterChainMatch buildFilterChainMatch(
int destPort, String... addressPrefix) {
ArrayList<EnvoyServerProtoData.CidrRange> prefixRanges = new ArrayList<>();
for (String address : addressPrefix) {
if (!Strings.isNullOrEmpty(address)) {
prefixRanges.add(new EnvoyServerProtoData.CidrRange(address, 32));
}
}
return new EnvoyServerProtoData.FilterChainMatch(
destPort, prefixRanges, Arrays.<String>asList());
}
}

View File

@ -43,7 +43,7 @@ import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext;
import io.grpc.xds.InternalXdsAttributes;
import io.grpc.xds.XdsClientWrapperForServerSds;
import io.grpc.xds.XdsClientWrapperForServerSdsTest;
import io.grpc.xds.XdsClientWrapperForServerSdsTestMisc;
import io.grpc.xds.internal.sds.SdsProtocolNegotiators.ClientSdsHandler;
import io.grpc.xds.internal.sds.SdsProtocolNegotiators.ClientSdsProtocolNegotiator;
import io.netty.channel.ChannelHandler;
@ -227,13 +227,18 @@ public class SdsProtocolNegotiatorsTest {
public SocketAddress localAddress() {
return new InetSocketAddress("172.168.1.1", 80);
}
@Override
public SocketAddress remoteAddress() {
return new InetSocketAddress("172.168.2.2", 90);
}
};
pipeline = channel.pipeline();
DownstreamTlsContext downstreamTlsContext =
buildDownstreamTlsContextFromFilenames(SERVER_1_KEY_FILE, SERVER_1_PEM_FILE, CA_PEM_FILE);
XdsClientWrapperForServerSds xdsClientWrapperForServerSds =
XdsClientWrapperForServerSdsTest.createXdsClientWrapperForServerSds(
XdsClientWrapperForServerSdsTestMisc.createXdsClientWrapperForServerSds(
80, downstreamTlsContext);
SdsProtocolNegotiators.HandlerPickerHandler handlerPickerHandler =
new SdsProtocolNegotiators.HandlerPickerHandler(grpcHandler, xdsClientWrapperForServerSds,
@ -281,7 +286,7 @@ public class SdsProtocolNegotiatorsTest {
.getDefaultInstance());
XdsClientWrapperForServerSds xdsClientWrapperForServerSds =
XdsClientWrapperForServerSdsTest.createXdsClientWrapperForServerSds(
XdsClientWrapperForServerSdsTestMisc.createXdsClientWrapperForServerSds(
80, downstreamTlsContext);
SdsProtocolNegotiators.HandlerPickerHandler handlerPickerHandler =
new SdsProtocolNegotiators.HandlerPickerHandler(