xds: replace PriorityHeap with simpler logic that keeps track of top matches (#8225)

This commit is contained in:
sanjaypujare 2021-06-02 10:09:42 -07:00 committed by GitHub
parent 1cd925c3dd
commit 54b4e93927
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 36 additions and 71 deletions

View File

@ -40,10 +40,8 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
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;
@ -307,88 +305,55 @@ public final class XdsClientWrapperForServerSds {
return cidrInt.equals(addrInt);
}
private static class QueueElement {
FilterChain filterChain;
int indexOfMatchingPrefixRange;
private static int getMatchingPrefixLength(
FilterChainMatch filterChainMatch, InetAddress address, boolean forDestination) {
byte[] addressBytes = address.getAddress();
boolean isIPv6 = address instanceof Inet6Address;
List<CidrRange> cidrRanges =
forDestination
? filterChainMatch.getPrefixRanges()
: filterChainMatch.getSourcePrefixRanges();
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 0-length match
matchingPrefixLength = 0;
} else {
matchingPrefixLength = -1;
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;
}
if (cidrRanges.isEmpty()) { // if there is no CidrRange assume 0-length match
matchingPrefixLength = 0;
} else {
matchingPrefixLength = -1;
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;
}
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();
}
return matchingPrefixLength;
}
// use prefix_ranges (CIDR) and get the most specific matches
private static 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());
// curent list of top ones
ArrayList<FilterChain> topOnes = new ArrayList<>(filterChains.size());
int topMatchingPrefixLen = -1;
while (!heap.isEmpty()) {
QueueElement element = heap.remove();
if (topMatchingPrefixLen == -1) {
topMatchingPrefixLen = element.matchingPrefixLength;
} else {
if (element.matchingPrefixLength < topMatchingPrefixLen) {
break;
for (FilterChain filterChain : filterChains) {
int currentMatchingPrefixLen =
getMatchingPrefixLength(filterChain.getFilterChainMatch(), address, forDestination);
if (currentMatchingPrefixLen >= 0) {
if (currentMatchingPrefixLen < topMatchingPrefixLen) {
continue;
}
if (currentMatchingPrefixLen > topMatchingPrefixLen) {
topMatchingPrefixLen = currentMatchingPrefixLen;
topOnes.clear();
}
topOnes.add(filterChain);
}
topOnes.add(element.filterChain);
}
return topOnes;
}