package org.ovirt.engine.core.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.LongRange;
import org.apache.commons.lang.math.Range;
import org.ovirt.engine.core.common.businessentities.MacRange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MacAddressRangeUtils {
private static final Logger log = LoggerFactory.getLogger(MacAddressRangeUtils.class);
private static final int HEX_RADIX = 16;
public static final long MAC_ADDRESS_MULTICAST_BIT = 0x010000000000L;
private MacAddressRangeUtils() {
}
public static List<String> macAddressesToStrings(List<Long> macAddresses) {
final List<String> result = new ArrayList<>(macAddresses.size());
for (Long macAddress : macAddresses) {
result.add(macToString(macAddress));
}
return result;
}
public static Collection<LongRange> parseRangeString(String ranges) {
if (StringUtils.isEmpty(ranges)) {
return Collections.emptyList();
}
String[] rangesArray = ranges.split("[,]", -1);
DisjointRanges disjointRanges = new DisjointRanges();
for (int i = 0; i < rangesArray.length; i++) {
String[] startEndArray = rangesArray[i].split("[-]", -1);
if (startEndArray.length == 2) {
disjointRanges.addRange(macToLong(startEndArray[0]), macToLong(startEndArray[1]));
} else {
throw new IllegalArgumentException(
"Failed to initialize Mac Pool range. Please fix Mac Pool range: rangesArray[i]");
}
}
return clipMultiCastsFromRanges(disjointRanges.getRanges());
}
public static Collection<LongRange> clipMultiCastsFromRanges(Collection<LongRange> ranges) {
final Collection<LongRange> result = new ArrayList<>();
for (LongRange range : ranges) {
final LongRange clippedRange = clipRange(range);
if (clippedRange != null) {
result.add(clippedRange);
}
}
return result;
}
public static LongRange clipRange(Range range) {
long rangeEnd = range.getMaximumLong();
long rangeStart = range.getMinimumLong();
boolean trimmingOccurred = false;
if (MacAddressRangeUtils.macIsMulticast(rangeStart)) {
rangeStart = (rangeStart | 0x00FFFFFFFFFFL) + 1;
trimmingOccurred = true;
}
final long trimmedRangeEnd = Math.min(rangeStart + Integer.MAX_VALUE - 1, rangeEnd);
if (rangeEnd != trimmedRangeEnd) {
rangeEnd = trimmedRangeEnd;
trimmingOccurred = true;
}
if (MacAddressRangeUtils.macIsMulticast(rangeEnd)) {
rangeEnd = (rangeEnd & 0xFF0000000000L) - 1;
trimmingOccurred = true;
}
if (rangeStart > rangeEnd) {
log.warn(
"User supplied range({}) contains only multicast addresses, so this range is not usable.", range);
return null;
}
final LongRange result = new LongRange(rangeStart, rangeEnd);
if (trimmingOccurred) {
log.warn("User supplied range({}) need to be trimmed to {}.", range, result);
}
return result;
}
public static boolean macIsMulticast(long mac) {
return (MAC_ADDRESS_MULTICAST_BIT & mac) != 0;
}
public static String macToString(long macAddress) {
String value = String.format("%012x", macAddress);
char[] chars = value.toCharArray();
final StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(chars[0]).append(chars[1]);
for (int pos = 2; pos < value.length(); pos += 2) {
stringBuilder.append(":")
.append(chars[pos])
.append(chars[pos + 1]);
}
return stringBuilder.toString();
}
public static long macToLong(String mac) {
log.debug("Processing MAC address: {}.", mac);
return Long.parseLong(StringUtils.remove(mac, ':'), HEX_RADIX);
}
public static boolean isRangeValid(String start, String end) {
long startNum = macToLong(start);
long endNum = macToLong(end);
if (startNum > endNum) {
return false;
}
Collection<LongRange> ranges = parseRangeString(start + "-" + end);
for (LongRange range : ranges) {
if (range.getMaximumLong() - range.getMinimumLong() < 0) {
return false;
}
}
return true;
}
public static Collection<LongRange> macPoolToRanges(org.ovirt.engine.core.common.businessentities.MacPool macPool) {
final DisjointRanges disjointRanges = new DisjointRanges();
for (MacRange macRange : macPool.getRanges()) {
disjointRanges.addRange(macToLong(macRange.getMacFrom()),
macToLong(macRange.getMacTo()));
}
return clipMultiCastsFromRanges(disjointRanges.getRanges());
}
}