blob: 8d8966f398e485480ce09b02e0fc86858d410bae [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Laboratory
*
* 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 org.onosproject.bmv2.api.utils;
import org.onlab.util.HexString;
import org.onlab.util.ImmutableByteSequence;
import java.util.Arrays;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Collection of util methods to deal with flow rule translation.
*/
public final class Bmv2TranslatorUtils {
private Bmv2TranslatorUtils() {
// Ban constructor.
}
/**
* Returns the number of bytes necessary to contain the given bit-width.
*
* @param bitWidth an integer value
* @return an integer value
*/
public static int roundToBytes(int bitWidth) {
return (int) Math.ceil((double) bitWidth / 8);
}
/**
* Trims or expands the given byte sequence so to fit a given bit-width.
*
* @param original a byte sequence
* @param bitWidth an integer value
* @return a new byte sequence
* @throws ByteSequenceFitException if the byte sequence cannot be fitted in the given bit-width
*/
public static ImmutableByteSequence fitByteSequence(ImmutableByteSequence original, int bitWidth)
throws ByteSequenceFitException {
checkNotNull(original, "byte sequence cannot be null");
checkArgument(bitWidth > 0, "byte width must a non-zero positive integer");
int newByteWidth = roundToBytes(bitWidth);
if (original.size() == newByteWidth) {
// nothing to do
return original;
}
byte[] originalBytes = original.asArray();
if (newByteWidth > original.size()) {
// pad missing bytes with zeros
return ImmutableByteSequence.copyFrom(Arrays.copyOf(originalBytes, newByteWidth));
}
byte[] newBytes = new byte[newByteWidth];
// ImmutableByteSequence is always big-endian, hence check the array in reverse order
int diff = originalBytes.length - newByteWidth;
for (int i = originalBytes.length - 1; i > 0; i--) {
byte ob = originalBytes[i]; // original byte
byte nb; // new byte
if (i > diff) {
// no need to truncate, copy as is
nb = ob;
} else if (i == diff) {
// truncate this byte, check if we're loosing something
byte mask = (byte) ((1 >> ((bitWidth % 8) + 1)) - 1);
if ((ob & ~mask) != 0) {
throw new ByteSequenceFitException(originalBytes, bitWidth);
} else {
nb = (byte) (ob & mask);
}
} else {
// drop this byte, check if we're loosing something
if (originalBytes[i] != 0) {
throw new ByteSequenceFitException(originalBytes, bitWidth);
} else {
continue;
}
}
newBytes[i - diff] = nb;
}
return ImmutableByteSequence.copyFrom(newBytes);
}
/**
* A byte sequence fit exception.
*/
public static class ByteSequenceFitException extends Exception {
public ByteSequenceFitException(byte[] bytes, int bitWidth) {
super("cannot fit " + HexString.toHexString(bytes) + " into a " + bitWidth + " bits value");
}
}
}