From 4d73514271a9caaa59b7a042d206ba4aad6b3fe0 Mon Sep 17 00:00:00 2001 From: Ed Warnicke Date: Sun, 10 Aug 2014 23:19:06 -0500 Subject: [PATCH] Fix to topology-lldp-discovery to allow for clean karaf feature Change-Id: Ife3388610a2d816f7bb8e5214cc98d123c4b604b Signed-off-by: Ed Warnicke --- opendaylight/commons/liblldp/pom.xml | 55 ++ .../controller/liblldp/BitBufferHelper.java | 718 ++++++++++++++++++ .../controller/liblldp/BufferException.java | 19 + .../liblldp/ConstructionException.java | 28 + .../controller/liblldp/DataLinkAddress.java | 96 +++ .../controller/liblldp/EtherTypes.java | 117 +++ .../controller/liblldp/Ethernet.java | 134 ++++ .../controller/liblldp/EthernetAddress.java | 124 +++ .../controller/liblldp/HexEncode.java | 114 +++ .../opendaylight/controller/liblldp/LLDP.java | 259 +++++++ .../controller/liblldp/LLDPTLV.java | 337 ++++++++ .../controller/liblldp/NetUtils.java | 521 +++++++++++++ .../controller/liblldp/Packet.java | 364 +++++++++ .../controller/liblldp/PacketException.java | 22 + .../sal/packet/BitBufferHelperTest.java | 693 +++++++++++++++++ .../packet/address/EthernetAddressTest.java | 114 +++ opendaylight/commons/opendaylight/pom.xml | 5 + .../distribution/opendaylight/pom.xml | 4 + .../md-sal/topology-lldp-discovery/pom.xml | 4 +- .../lldp/utils/LLDPDiscoveryUtils.java | 8 +- pom.xml | 1 + 21 files changed, 3731 insertions(+), 6 deletions(-) create mode 100644 opendaylight/commons/liblldp/pom.xml create mode 100644 opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BitBufferHelper.java create mode 100644 opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BufferException.java create mode 100644 opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/ConstructionException.java create mode 100644 opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/DataLinkAddress.java create mode 100644 opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EtherTypes.java create mode 100644 opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Ethernet.java create mode 100644 opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EthernetAddress.java create mode 100644 opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/HexEncode.java create mode 100644 opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDP.java create mode 100644 opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDPTLV.java create mode 100644 opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/NetUtils.java create mode 100644 opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Packet.java create mode 100644 opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/PacketException.java create mode 100644 opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/BitBufferHelperTest.java create mode 100644 opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/address/EthernetAddressTest.java diff --git a/opendaylight/commons/liblldp/pom.xml b/opendaylight/commons/liblldp/pom.xml new file mode 100644 index 0000000000..1551041edb --- /dev/null +++ b/opendaylight/commons/liblldp/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + org.opendaylight.controller + commons.opendaylight + 1.4.2-SNAPSHOT + ../opendaylight + + + liblldp + 0.8.1-SNAPSHOT + bundle + + + junit + junit + + + org.apache.commons + commons-lang3 + + + org.slf4j + slf4j-api + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + org.slf4j, + org.apache.commons.lang3.builder, + org.apache.commons.lang3.tuple + + + org.opendaylight.controller.liblldp + + ${project.basedir}/META-INF + + + + + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + HEAD + https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main + + diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BitBufferHelper.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BitBufferHelper.java new file mode 100644 index 0000000000..3eae43212f --- /dev/null +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BitBufferHelper.java @@ -0,0 +1,718 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +/** + * + */ +package org.opendaylight.controller.liblldp; + +import java.util.Arrays; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * BitBufferHelper class that provides utility methods to + * - fetch specific bits from a serialized stream of bits + * - convert bits to primitive data type - like short, int, long + * - store bits in specified location in stream of bits + * - convert primitive data types to stream of bits + */ +public abstract class BitBufferHelper { + protected static final Logger logger = LoggerFactory + .getLogger(BitBufferHelper.class); + + public static final long ByteMask = 0xFF; + + // Getters + // data: array where data are stored + // startOffset: bit from where to start reading + // numBits: number of bits to read + // All this function return an exception if overflow or underflow + + /** + * Returns the first byte from the byte array + * @param byte[] data + * @return byte value + */ + public static byte getByte(byte[] data) { + if ((data.length * NetUtils.NumBitsInAByte) > Byte.SIZE) { + try { + throw new BufferException( + "Container is too small for the number of requested bits"); + } catch (BufferException e) { + logger.error("", e); + } + } + return (data[0]); + } + + /** + * Returns the short value for the byte array passed. + * Size of byte array is restricted to Short.SIZE + * @param byte[] data + * @return short value + */ + public static short getShort(byte[] data) { + if (data.length > Short.SIZE) { + try { + throw new BufferException( + "Container is too small for the number of requested bits"); + } catch (BufferException e) { + logger.error("", e); + } + } + return (short) toNumber(data); + } + + /** + * Returns the int value for the byte array passed. + * Size of byte array is restricted to Integer.SIZE + * @param byte[] data + * @return int - the integer value of byte array + */ + public static int getInt(byte[] data) { + if (data.length > Integer.SIZE) { + try { + throw new BufferException( + "Container is too small for the number of requested bits"); + } catch (BufferException e) { + logger.error("", e); + } + } + return (int) toNumber(data); + } + + /** + * Returns the long value for the byte array passed. + * Size of byte array is restricted to Long.SIZE + * @param byte[] data + * @return long - the integer value of byte array + */ + public static long getLong(byte[] data) { + if (data.length > Long.SIZE) { + try { + throw new BufferException( + "Container is too small for the number of requested bits"); + } catch (Exception e) { + logger.error("", e); + } + } + return (long) toNumber(data); + } + + /** + * Returns the short value for the last numBits of the byte array passed. + * Size of numBits is restricted to Short.SIZE + * @param byte[] data + * @param int - numBits + * @return short - the short value of byte array + */ + public static short getShort(byte[] data, int numBits) { + if (numBits > Short.SIZE) { + try { + throw new BufferException( + "Container is too small for the number of requested bits"); + } catch (BufferException e) { + logger.error("", e); + } + } + int startOffset = data.length * NetUtils.NumBitsInAByte - numBits; + byte[] bits = null; + try { + bits = BitBufferHelper.getBits(data, startOffset, numBits); + } catch (BufferException e) { + logger.error("", e); + } + return (short) toNumber(bits, numBits); + } + + /** + * Returns the int value for the last numBits of the byte array passed. + * Size of numBits is restricted to Integer.SIZE + * @param byte[] data + * @param int - numBits + * @return int - the integer value of byte array + */ + public static int getInt(byte[] data, int numBits) { + if (numBits > Integer.SIZE) { + try { + throw new BufferException( + "Container is too small for the number of requested bits"); + } catch (BufferException e) { + logger.error("", e); + } + } + int startOffset = data.length * NetUtils.NumBitsInAByte - numBits; + byte[] bits = null; + try { + bits = BitBufferHelper.getBits(data, startOffset, numBits); + } catch (BufferException e) { + logger.error("", e); + } + return (int) toNumber(bits, numBits); + } + + /** + * Returns the long value for the last numBits of the byte array passed. + * Size of numBits is restricted to Long.SIZE + * @param byte[] data + * @param int - numBits + * @return long - the integer value of byte array + */ + public static long getLong(byte[] data, int numBits) { + if (numBits > Long.SIZE) { + try { + throw new BufferException( + "Container is too small for the number of requested bits"); + } catch (BufferException e) { + logger.error("", e); + } + } + if (numBits > data.length * NetUtils.NumBitsInAByte) { + try { + throw new BufferException( + "Trying to read more bits than contained in the data buffer"); + } catch (BufferException e) { + logger.error("", e); + } + } + int startOffset = data.length * NetUtils.NumBitsInAByte - numBits; + byte[] bits = null; + try { + bits = BitBufferHelper.getBits(data, startOffset, numBits); + } catch (BufferException e) { + logger.error("", e); + } + return (long) toNumber(bits, numBits); + } + + /** + * Reads the specified number of bits from the passed byte array + * starting to read from the specified offset + * The bits read are stored in a byte array which size is dictated + * by the number of bits to be stored. + * The bits are stored in the byte array LSB aligned. + * + * Ex. + * Read 7 bits at offset 10 + * 0 9 10 16 17 + * 0101000010 | 0000101 | 1111001010010101011 + * will be returned as {0,0,0,0,0,1,0,1} + * + * @param byte[] data + * @param int startOffset - offset to start fetching bits from data from + * @param int numBits - number of bits to be fetched from data + * @return byte [] - LSB aligned bits + * + * @throws BufferException + * when the startOffset and numBits parameters are not congruent + * with the data buffer size + */ + public static byte[] getBits(byte[] data, int startOffset, int numBits) + throws BufferException { + + int startByteOffset = 0; + int valfromcurr, valfromnext; + int extranumBits = numBits % NetUtils.NumBitsInAByte; + int extraOffsetBits = startOffset % NetUtils.NumBitsInAByte; + int numBytes = (numBits % NetUtils.NumBitsInAByte != 0) ? 1 + numBits + / NetUtils.NumBitsInAByte : numBits / NetUtils.NumBitsInAByte; + byte[] shiftedBytes = new byte[numBytes]; + startByteOffset = startOffset / NetUtils.NumBitsInAByte; + byte[] bytes = new byte[numBytes]; + if (numBits == 0) { + return bytes; + } + + checkExceptions(data, startOffset, numBits); + + if (extraOffsetBits == 0) { + if (extranumBits == 0) { + System.arraycopy(data, startByteOffset, bytes, 0, numBytes); + return bytes; + } else { + System.arraycopy(data, startByteOffset, bytes, 0, numBytes - 1); + bytes[numBytes - 1] = (byte) ((int) data[startByteOffset + + numBytes - 1] & getMSBMask(extranumBits)); + } + } else { + int i; + for (i = 0; i < numBits / NetUtils.NumBitsInAByte; i++) { + // Reading numBytes starting from offset + valfromcurr = (data[startByteOffset + i]) + & getLSBMask(NetUtils.NumBitsInAByte - extraOffsetBits); + valfromnext = (data[startByteOffset + i + 1]) + & getMSBMask(extraOffsetBits); + bytes[i] = (byte) (valfromcurr << (extraOffsetBits) | (valfromnext >> (NetUtils.NumBitsInAByte - extraOffsetBits))); + } + // Now adding the rest of the bits if any + if (extranumBits != 0) { + if (extranumBits < (NetUtils.NumBitsInAByte - extraOffsetBits)) { + valfromnext = (byte) (data[startByteOffset + i] & ((getMSBMask(extranumBits)) >> extraOffsetBits)); + bytes[i] = (byte) (valfromnext << extraOffsetBits); + } else if (extranumBits == (NetUtils.NumBitsInAByte - extraOffsetBits)) { + valfromcurr = (data[startByteOffset + i]) + & getLSBMask(NetUtils.NumBitsInAByte + - extraOffsetBits); + bytes[i] = (byte) (valfromcurr << extraOffsetBits); + } else { + valfromcurr = (data[startByteOffset + i]) + & getLSBMask(NetUtils.NumBitsInAByte + - extraOffsetBits); + valfromnext = (data[startByteOffset + i + 1]) + & (getMSBMask(extranumBits + - (NetUtils.NumBitsInAByte - extraOffsetBits))); + bytes[i] = (byte) (valfromcurr << (extraOffsetBits) | (valfromnext >> (NetUtils.NumBitsInAByte - extraOffsetBits))); + } + + } + } + // Aligns the bits to LSB + shiftedBytes = shiftBitsToLSB(bytes, numBits); + return shiftedBytes; + } + + // Setters + // data: array where data will be stored + // input: the data that need to be stored in the data array + // startOffset: bit from where to start writing + // numBits: number of bits to read + + /** + * Bits are expected to be stored in the input byte array from LSB + * @param byte[] - data to set the input byte + * @param byte - input byte to be inserted + * @param startOffset - offset of data[] to start inserting byte from + * @param numBits - number of bits of input to be inserted into data[] + * + * @throws BufferException + * when the input, startOffset and numBits are not congruent + * with the data buffer size + */ + public static void setByte(byte[] data, byte input, int startOffset, + int numBits) throws BufferException { + byte[] inputByteArray = new byte[1]; + Arrays.fill(inputByteArray, 0, 1, input); + setBytes(data, inputByteArray, startOffset, numBits); + } + + /** + * Bits are expected to be stored in the input byte array from LSB + * @param byte[] - data to set the input byte + * @param byte[] - input bytes to be inserted + * @param startOffset - offset of data[] to start inserting byte from + * @param numBits - number of bits of input to be inserted into data[] + * @return void + * @throws BufferException + * when the startOffset and numBits parameters are not congruent + * with data and input buffers' size + */ + public static void setBytes(byte[] data, byte[] input, int startOffset, + int numBits) throws BufferException { + checkExceptions(data, startOffset, numBits); + insertBits(data, input, startOffset, numBits); + } + + /** + * Returns numBits 1's in the MSB position + * + * @param numBits + * @return + */ + public static int getMSBMask(int numBits) { + int mask = 0; + for (int i = 0; i < numBits; i++) { + mask = mask | (1 << (7 - i)); + } + return mask; + } + + /** + * Returns numBits 1's in the LSB position + * + * @param numBits + * @return + */ + public static int getLSBMask(int numBits) { + int mask = 0; + for (int i = 0; i < numBits; i++) { + mask = mask | (1 << i); + } + return mask; + } + + /** + * Returns the numerical value of the byte array passed + * + * @param byte[] - array + * @return long - numerical value of byte array passed + */ + static public long toNumber(byte[] array) { + long ret = 0; + long length = array.length; + int value = 0; + for (int i = 0; i < length; i++) { + value = array[i]; + if (value < 0) + value += 256; + ret = ret + | (long) ((long) value << ((length - i - 1) * NetUtils.NumBitsInAByte)); + } + return ret; + } + + /** + * Returns the numerical value of the last numBits (LSB bits) of the byte + * array passed + * + * @param byte[] - array + * @param int - numBits + * @return long - numerical value of byte array passed + */ + static public long toNumber(byte[] array, int numBits) { + int length = numBits / NetUtils.NumBitsInAByte; + int bitsRest = numBits % NetUtils.NumBitsInAByte; + int startOffset = array.length - length; + long ret = 0; + int value = 0; + + value = array[startOffset - 1] & getLSBMask(bitsRest); + value = (array[startOffset - 1] < 0) ? (array[startOffset - 1] + 256) + : array[startOffset - 1]; + ret = ret + | (value << ((array.length - startOffset) * NetUtils.NumBitsInAByte)); + + for (int i = startOffset; i < array.length; i++) { + value = array[i]; + if (value < 0) + value += 256; + ret = ret + | (long) ((long) value << ((array.length - i - 1) * NetUtils.NumBitsInAByte)); + } + + return ret; + } + + /** + * Accepts a number as input and returns its value in byte form in LSB + * aligned form example: input = 5000 [1001110001000] bytes = 19, -120 + * [00010011] [10001000] + * + * @param Number + * @return byte[] + * + */ + + public static byte[] toByteArray(Number input) { + Class dataType = input.getClass(); + short size = 0; + long longValue = input.longValue(); + + if (dataType == Byte.class || dataType == byte.class) { + size = Byte.SIZE; + } else if (dataType == Short.class || dataType == short.class) { + size = Short.SIZE; + } else if (dataType == Integer.class || dataType == int.class) { + size = Integer.SIZE; + } else if (dataType == Long.class || dataType == long.class) { + size = Long.SIZE; + } else { + throw new IllegalArgumentException( + "Parameter must one of the following: Short/Int/Long\n"); + } + + int length = size / NetUtils.NumBitsInAByte; + byte bytes[] = new byte[length]; + + // Getting the bytes from input value + for (int i = 0; i < length; i++) { + bytes[i] = (byte) ((longValue >> (NetUtils.NumBitsInAByte * (length + - i - 1))) & ByteMask); + } + return bytes; + } + + /** + * Accepts a number as input and returns its value in byte form in MSB + * aligned form example: input = 5000 [1001110001000] bytes = -114, 64 + * [10011100] [01000000] + * + * @param Number + * input + * @param int numBits - the number of bits to be returned + * @return byte[] + * + */ + public static byte[] toByteArray(Number input, int numBits) { + Class dataType = input.getClass(); + short size = 0; + long longValue = input.longValue(); + + if (dataType == Short.class) { + size = Short.SIZE; + } else if (dataType == Integer.class) { + size = Integer.SIZE; + } else if (dataType == Long.class) { + size = Long.SIZE; + } else { + throw new IllegalArgumentException( + "Parameter must one of the following: Short/Int/Long\n"); + } + + int length = size / NetUtils.NumBitsInAByte; + byte bytes[] = new byte[length]; + byte[] inputbytes = new byte[length]; + byte shiftedBytes[]; + + // Getting the bytes from input value + for (int i = 0; i < length; i++) { + bytes[i] = (byte) ((longValue >> (NetUtils.NumBitsInAByte * (length + - i - 1))) & ByteMask); + } + + if ((bytes[0] == 0 && dataType == Long.class) + || (bytes[0] == 0 && dataType == Integer.class)) { + int index = 0; + for (index = 0; index < length; ++index) { + if (bytes[index] != 0) { + bytes[0] = bytes[index]; + break; + } + } + System.arraycopy(bytes, index, inputbytes, 0, length - index); + Arrays.fill(bytes, length - index + 1, length - 1, (byte) 0); + } else { + System.arraycopy(bytes, 0, inputbytes, 0, length); + } + + shiftedBytes = shiftBitsToMSB(inputbytes, numBits); + + return shiftedBytes; + } + + /** + * Takes an LSB aligned byte array and returned the LSB numBits in a MSB + * aligned byte array + * + * @param inputbytes + * @param numBits + * @return + */ + /** + * It aligns the last numBits bits to the head of the byte array following + * them with numBits % 8 zero bits. + * + * Example: For inputbytes = [00000111][01110001] and numBits = 12 it + * returns: shiftedBytes = [01110111][00010000] + * + * @param byte[] inputBytes + * @param int numBits - number of bits to be left aligned + * @return byte[] + */ + public static byte[] shiftBitsToMSB(byte[] inputBytes, int numBits) { + int numBitstoShiftBy = 0, leadZeroesMSB = 8, numEndRestBits = 0; + int size = inputBytes.length; + byte[] shiftedBytes = new byte[size]; + int i; + + for (i = 0; i < Byte.SIZE; i++) { + if (((byte) (inputBytes[0] & getMSBMask(i + 1))) != 0) { + leadZeroesMSB = i; + break; + } + } + + if (numBits % NetUtils.NumBitsInAByte == 0) { + numBitstoShiftBy = 0; + } else { + numBitstoShiftBy = ((NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte)) < leadZeroesMSB) ? (NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte)) + : leadZeroesMSB; + } + if (numBitstoShiftBy == 0) { + return inputBytes; + } + + if (numBits < NetUtils.NumBitsInAByte) { + // inputbytes.length = 1 OR read less than a byte + shiftedBytes[0] = (byte) ((inputBytes[0] & getLSBMask(numBits)) << numBitstoShiftBy); + } else { + // # of bits to read from last byte + numEndRestBits = NetUtils.NumBitsInAByte + - (inputBytes.length * NetUtils.NumBitsInAByte - numBits - numBitstoShiftBy); + + for (i = 0; i < (size - 1); i++) { + if ((i + 1) == (size - 1)) { + if (numEndRestBits > numBitstoShiftBy) { + shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (numEndRestBits - numBitstoShiftBy))); + shiftedBytes[i + 1] = (byte) ((inputBytes[i + 1] & getLSBMask(numEndRestBits + - numBitstoShiftBy)) << numBitstoShiftBy); + } else + shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numEndRestBits)) >> (NetUtils.NumBitsInAByte - numEndRestBits))); + } + shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | (inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (NetUtils.NumBitsInAByte - numBitstoShiftBy)); + } + + } + return shiftedBytes; + } + + /** + * It aligns the first numBits bits to the right end of the byte array + * preceding them with numBits % 8 zero bits. + * + * Example: For inputbytes = [01110111][00010000] and numBits = 12 it + * returns: shiftedBytes = [00000111][01110001] + * + * @param byte[] inputBytes + * @param int numBits - number of bits to be right aligned + * @return byte[] + */ + public static byte[] shiftBitsToLSB(byte[] inputBytes, int numBits) { + int numBytes = inputBytes.length; + int numBitstoShift = numBits % NetUtils.NumBitsInAByte; + byte[] shiftedBytes = new byte[numBytes]; + int inputLsb = 0, inputMsb = 0; + + if (numBitstoShift == 0) { + return inputBytes; + } + + for (int i = 1; i < numBytes; i++) { + inputLsb = inputBytes[i - 1] + & getLSBMask(NetUtils.NumBitsInAByte - numBitstoShift); + inputLsb = (inputLsb < 0) ? (inputLsb + 256) : inputLsb; + inputMsb = inputBytes[i] & getMSBMask(numBitstoShift); + inputMsb = (inputBytes[i] < 0) ? (inputBytes[i] + 256) + : inputBytes[i]; + shiftedBytes[i] = (byte) ((inputLsb << numBitstoShift) | (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift))); + } + inputMsb = inputBytes[0] & (getMSBMask(numBitstoShift)); + inputMsb = (inputMsb < 0) ? (inputMsb + 256) : inputMsb; + shiftedBytes[0] = (byte) (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift)); + return shiftedBytes; + } + + /** + * Insert in the data buffer at position dictated by the offset the number + * of bits specified from the input data byte array. The input byte array + * has the bits stored starting from the LSB + * + * @param byte[] data + * @param byte[] inputdata + * @param int startOffset + * @param int numBits + */ + public static void insertBits(byte[] data, byte[] inputdataLSB, + int startOffset, int numBits) { + byte[] inputdata = shiftBitsToMSB(inputdataLSB, numBits); // Align to + // MSB the + // passed byte + // array + int numBytes = numBits / NetUtils.NumBitsInAByte; + int startByteOffset = startOffset / NetUtils.NumBitsInAByte; + int extraOffsetBits = startOffset % NetUtils.NumBitsInAByte; + int extranumBits = numBits % NetUtils.NumBitsInAByte; + int RestBits = numBits % NetUtils.NumBitsInAByte; + int InputMSBbits = 0, InputLSBbits = 0; + int i; + + if (numBits == 0) { + return; + } + + if (extraOffsetBits == 0) { + if (extranumBits == 0) { + numBytes = numBits / NetUtils.NumBitsInAByte; + System.arraycopy(inputdata, 0, data, startByteOffset, numBytes); + } else { + System.arraycopy(inputdata, 0, data, startByteOffset, numBytes); + data[startByteOffset + numBytes] = (byte) (data[startByteOffset + + numBytes] | (inputdata[numBytes] & getMSBMask(extranumBits))); + } + } else { + for (i = 0; i < numBytes; i++) { + if (i != 0) + InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits)); + InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte + - extraOffsetBits))); + InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits + : InputMSBbits + 256; + data[startByteOffset + i] = (byte) (data[startByteOffset + i] + | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits)); + InputMSBbits = InputLSBbits = 0; + } + if (RestBits < (NetUtils.NumBitsInAByte - extraOffsetBits)) { + if (numBytes != 0) + InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits)); + InputMSBbits = (byte) (inputdata[i] & (getMSBMask(RestBits))); + InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits + : InputMSBbits + 256; + data[startByteOffset + i] = (byte) ((data[startByteOffset + i]) + | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits)); + } else if (RestBits == (NetUtils.NumBitsInAByte - extraOffsetBits)) { + if (numBytes != 0) + InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits)); + InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte + - extraOffsetBits))); + InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits + : InputMSBbits + 256; + data[startByteOffset + i] = (byte) (data[startByteOffset + i] + | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits)); + } else { + if (numBytes != 0) + InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits)); + InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte + - extraOffsetBits))); + InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits + : InputMSBbits + 256; + data[startByteOffset + i] = (byte) (data[startByteOffset + i] + | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits)); + + InputLSBbits = (inputdata[i] & (getLSBMask(RestBits + - (NetUtils.NumBitsInAByte - extraOffsetBits)) << (NetUtils.NumBitsInAByte - RestBits))); + data[startByteOffset + i + 1] = (byte) (data[startByteOffset + + i + 1] | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits))); + } + } + } + + /** + * Checks for overflow and underflow exceptions + * @param data + * @param startOffset + * @param numBits + * @throws PacketException when the startOffset and numBits parameters + * are not congruent with the data buffer's size + */ + public static void checkExceptions(byte[] data, int startOffset, int numBits) + throws BufferException { + int endOffsetByte; + int startByteOffset; + endOffsetByte = startOffset + / NetUtils.NumBitsInAByte + + numBits + / NetUtils.NumBitsInAByte + + ((numBits % NetUtils.NumBitsInAByte != 0) ? 1 : ((startOffset + % NetUtils.NumBitsInAByte != 0) ? 1 : 0)); + startByteOffset = startOffset / NetUtils.NumBitsInAByte; + + if (data == null) { + throw new BufferException("data[] is null\n"); + } + + if ((startOffset < 0) || (startByteOffset >= data.length) + || (endOffsetByte > data.length) || (numBits < 0) + || (numBits > NetUtils.NumBitsInAByte * data.length)) { + throw new BufferException( + "Illegal arguement/out of bound exception - data.length = " + + data.length + " startOffset = " + startOffset + + " numBits " + numBits); + } + } +} diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BufferException.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BufferException.java new file mode 100644 index 0000000000..fa0848d894 --- /dev/null +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BufferException.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.liblldp; + +/** + * Describes an exception that is raised during BitBufferHelper operations. + */ +public class BufferException extends Exception { + private static final long serialVersionUID = 1L; + + public BufferException(String message) { + super(message); + } +} diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/ConstructionException.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/ConstructionException.java new file mode 100644 index 0000000000..8b1d9d2d0f --- /dev/null +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/ConstructionException.java @@ -0,0 +1,28 @@ + +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +/** + * @file ConstructionException.java + * + * + * @brief Describe an exception that is raised when a construction + * for a Node/NodeConnector/Edge or any of the SAL basic object fails + * because input passed are not valid or compatible + * + * + */ +package org.opendaylight.controller.liblldp; + +public class ConstructionException extends Exception { + private static final long serialVersionUID = 1L; + + public ConstructionException(String message) { + super(message); + } +} diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/DataLinkAddress.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/DataLinkAddress.java new file mode 100644 index 0000000000..d617c05a5a --- /dev/null +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/DataLinkAddress.java @@ -0,0 +1,96 @@ + +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.liblldp; + +import java.io.Serializable; + +import javax.xml.bind.annotation.XmlRootElement; + +/** + * @file DataLinkAddress.java + * + * @brief Abstract base class for a Datalink Address + * + */ + +/** + * Abstract base class for a Datalink Address + * + */ +@XmlRootElement +abstract public class DataLinkAddress implements Serializable { + private static final long serialVersionUID = 1L; + private String name; + + public DataLinkAddress() { + + } + + /** + * Constructor of super class + * + * @param name Create a new DataLink, not for general use but + * available only for sub classes + * + * @return constructed object + */ + protected DataLinkAddress(String name) { + this.name = name; + } + + /** + * Used to copy the DataLinkAddress in a polymorphic way + * + * + * @return A clone of this DataLinkAddress + */ + @Override + abstract public DataLinkAddress clone(); + + /** + * Allow to distinguish among different data link addresses + * + * + * @return Name of the DataLinkAdress we are working on + */ + public String getName() { + return this.name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + DataLinkAddress other = (DataLinkAddress) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + @Override + public String toString() { + return "DataLinkAddress [name=" + name + "]"; + } +} diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EtherTypes.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EtherTypes.java new file mode 100644 index 0000000000..876d495899 --- /dev/null +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EtherTypes.java @@ -0,0 +1,117 @@ + +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.liblldp; + +import java.util.ArrayList; +import java.util.List; + +/** + * The enum contains the most common 802.3 ethernet types and 802.2 + SNAP protocol ids + * + * + * + */ +public enum EtherTypes { + PVSTP("PVSTP", 0x010B), // 802.2 + SNAP (Spanning Tree) + CDP("CDP", 0x2000), // 802.2 + SNAP + VTP("VTP", 0x2003), // 802.2 + SNAP + IPv4("IPv4", 0x800), ARP("ARP", 0x806), RARP("Reverse ARP", 0x8035), VLANTAGGED( + "VLAN Tagged", 0x8100), // 802.1Q + IPv6("IPv6", 0x86DD), MPLSUCAST("MPLS Unicast", 0x8847), MPLSMCAST( + "MPLS Multicast", 0x8848), QINQ("QINQ", 0x88A8), // Standard 802.1ad QinQ + LLDP("LLDP", 0x88CC), OLDQINQ("Old QINQ", 0x9100), // Old non-standard QinQ + CISCOQINQ("Cisco QINQ", 0x9200); // Cisco non-standard QinQ + + private static final String regexNumberString = "^[0-9]+$"; + private String description; + private int number; + + private EtherTypes(String description, int number) { + this.description = description; + this.number = number; + } + + public String toString() { + return description; + } + + public int intValue() { + return number; + } + + public short shortValue() { + return ((Integer) number).shortValue(); + } + + public static String getEtherTypeName(int number) { + return getEtherTypeInternal(number); + } + + public static String getEtherTypeName(short number) { + return getEtherTypeInternal((int) number & 0xffff); + } + + public static String getEtherTypeName(byte number) { + return getEtherTypeInternal((int) number & 0xff); + } + + private static String getEtherTypeInternal(int number) { + for (EtherTypes type : EtherTypes.values()) { + if (type.number == number) { + return type.toString(); + } + } + return "0x" + Integer.toHexString(number); + } + + public static short getEtherTypeNumberShort(String name) { + if (name.matches(regexNumberString)) { + return Short.valueOf(name); + } + for (EtherTypes type : EtherTypes.values()) { + if (type.description.equalsIgnoreCase(name)) { + return type.shortValue(); + } + } + return 0; + } + + public static int getEtherTypeNumberInt(String name) { + if (name.matches(regexNumberString)) { + return Integer.valueOf(name); + } + for (EtherTypes type : EtherTypes.values()) { + if (type.description.equalsIgnoreCase(name)) { + return type.intValue(); + } + } + return 0; + } + + public static List getEtherTypesNameList() { + List ethertypesList = new ArrayList(); + for (EtherTypes type : EtherTypes.values()) { + ethertypesList.add(type.toString()); + } + return ethertypesList; + } + + public static EtherTypes loadFromString(String string) { + int intType = Integer.parseInt(string); + + for (EtherTypes type : EtherTypes.values()) { + if (type.number == intType) { + return type; + } + } + return null; + } + +} diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Ethernet.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Ethernet.java new file mode 100644 index 0000000000..54452bb9a4 --- /dev/null +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Ethernet.java @@ -0,0 +1,134 @@ + +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.liblldp; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +/** + * Class that represents the Ethernet frame objects + */ +public class Ethernet extends Packet { + private static final String DMAC = "DestinationMACAddress"; + private static final String SMAC = "SourceMACAddress"; + private static final String ETHT = "EtherType"; + + // TODO: This has to be outside and it should be possible for osgi + // to add new coming packet classes + public static final Map> etherTypeClassMap; + static { + etherTypeClassMap = new HashMap>(); + etherTypeClassMap.put(EtherTypes.LLDP.shortValue(), LLDP.class); + } + private static Map> fieldCoordinates = new LinkedHashMap>() { + private static final long serialVersionUID = 1L; + { + put(DMAC, new ImmutablePair(0, 48)); + put(SMAC, new ImmutablePair(48, 48)); + put(ETHT, new ImmutablePair(96, 16)); + } + }; + private final Map fieldValues; + + /** + * Default constructor that creates and sets the HashMap + */ + public Ethernet() { + super(); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + } + + /** + * Constructor that sets the access level for the packet and + * creates and sets the HashMap + */ + public Ethernet(boolean writeAccess) { + super(writeAccess); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + } + + @Override + public void setHeaderField(String headerField, byte[] readValue) { + if (headerField.equals(ETHT)) { + payloadClass = etherTypeClassMap.get(BitBufferHelper + .getShort(readValue)); + } + hdrFieldsMap.put(headerField, readValue); + } + + /** + * Gets the destination MAC address stored + * @return byte[] - the destinationMACAddress + */ + public byte[] getDestinationMACAddress() { + return fieldValues.get(DMAC); + } + + /** + * Gets the source MAC address stored + * @return byte[] - the sourceMACAddress + */ + public byte[] getSourceMACAddress() { + return fieldValues.get(SMAC); + } + + /** + * Gets the etherType stored + * @return short - the etherType + */ + public short getEtherType() { + return BitBufferHelper.getShort(fieldValues.get(ETHT)); + } + + public boolean isBroadcast(){ + return NetUtils.isBroadcastMACAddr(getDestinationMACAddress()); + } + + public boolean isMulticast(){ + return NetUtils.isMulticastMACAddr(getDestinationMACAddress()); + } + + /** + * Sets the destination MAC address for the current Ethernet object instance + * @param byte[] - the destinationMACAddress to set + */ + public Ethernet setDestinationMACAddress(byte[] destinationMACAddress) { + fieldValues.put(DMAC, destinationMACAddress); + return this; + } + + /** + * Sets the source MAC address for the current Ethernet object instance + * @param byte[] - the sourceMACAddress to set + */ + public Ethernet setSourceMACAddress(byte[] sourceMACAddress) { + fieldValues.put(SMAC, sourceMACAddress); + return this; + } + + /** + * Sets the etherType for the current Ethernet object instance + * @param short - the etherType to set + */ + public Ethernet setEtherType(short etherType) { + byte[] ethType = BitBufferHelper.toByteArray(etherType); + fieldValues.put(ETHT, ethType); + return this; + } + +} diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EthernetAddress.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EthernetAddress.java new file mode 100644 index 0000000000..b7b72cbffd --- /dev/null +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EthernetAddress.java @@ -0,0 +1,124 @@ + +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.liblldp; + +import java.util.Arrays; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlTransient; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) +public class EthernetAddress extends DataLinkAddress { + private static final long serialVersionUID = 1L; + @XmlTransient + private byte[] macAddress; + + public static final EthernetAddress BROADCASTMAC = createWellKnownAddress(new byte[] { + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff }); + + public static final EthernetAddress INVALIDHOST = BROADCASTMAC; + + public static final String addressName = "Ethernet MAC Address"; + public static final int SIZE = 6; + + private static final EthernetAddress createWellKnownAddress(byte[] mac) { + try { + return new EthernetAddress(mac); + } catch (ConstructionException ce) { + return null; + } + } + + /* Private constructor to satisfy JAXB */ + @SuppressWarnings("unused") + private EthernetAddress() { + } + + /** + * Public constructor for an Ethernet MAC address starting from + * the byte constituing the address, the constructor validate the + * size of the arrive to make sure it met the expected size + * + * @param macAddress A byte array in big endian format + * representing the Ethernet MAC Address + * + * @return The constructed object if valid + */ + public EthernetAddress(byte[] macAddress) throws ConstructionException { + super(addressName); + + if (macAddress == null) { + throw new ConstructionException("Null input parameter passed"); + } + + if (macAddress.length != SIZE) { + throw new ConstructionException( + "Wrong size of passed byte array, expected:" + SIZE + + " got:" + macAddress.length); + } + this.macAddress = new byte[SIZE]; + System.arraycopy(macAddress, 0, this.macAddress, 0, SIZE); + } + + public EthernetAddress clone() { + try { + return new EthernetAddress(this.macAddress.clone()); + } catch (ConstructionException ce) { + return null; + } + } + + /** + * Return the Ethernet Mac address in byte array format + * + * @return The Ethernet Mac address in byte array format + */ + public byte[] getValue() { + return this.macAddress; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + Arrays.hashCode(macAddress); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + EthernetAddress other = (EthernetAddress) obj; + if (!Arrays.equals(macAddress, other.macAddress)) + return false; + return true; + } + + @Override + public String toString() { + return "EthernetAddress [macAddress=" + HexEncode.bytesToHexStringFormat(macAddress) + + "]"; + } + + @XmlElement(name = "macAddress") + public String getMacAddress() { + return HexEncode.bytesToHexStringFormat(macAddress); + } +} diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/HexEncode.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/HexEncode.java new file mode 100644 index 0000000000..8236d4c3c9 --- /dev/null +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/HexEncode.java @@ -0,0 +1,114 @@ + +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.liblldp; + +import java.math.BigInteger; + +/** + * The class provides methods to convert hex encode strings + * + * + */ +public class HexEncode { + /** + * This method converts byte array into String format without ":" inserted. + * + * @param bytes + * The byte array to convert to string + * @return The hexadecimal representation of the byte array. If bytes is + * null, "null" string is returned + */ + public static String bytesToHexString(byte[] bytes) { + + if (bytes == null) { + return "null"; + } + + String ret = ""; + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + if (i > 0) { + ret += ":"; + } + short u8byte = (short) (bytes[i] & 0xff); + String tmp = Integer.toHexString(u8byte); + if (tmp.length() == 1) { + buf.append("0"); + } + buf.append(tmp); + } + ret = buf.toString(); + return ret; + } + + public static String longToHexString(long val) { + char arr[] = Long.toHexString(val).toCharArray(); + StringBuffer buf = new StringBuffer(); + // prepend the right number of leading zeros + int i = 0; + for (; i < (16 - arr.length); i++) { + buf.append("0"); + if ((i & 0x01) == 1) { + buf.append(":"); + } + } + for (int j = 0; j < arr.length; j++) { + buf.append(arr[j]); + if ((((i + j) & 0x01) == 1) && (j < (arr.length - 1))) { + buf.append(":"); + } + } + return buf.toString(); + } + + + public static byte[] bytesFromHexString(String values) { + String target = ""; + if (values != null) { + target = values; + } + String[] octets = target.split(":"); + + byte[] ret = new byte[octets.length]; + for (int i = 0; i < octets.length; i++) { + ret[i] = Integer.valueOf(octets[i], 16).byteValue(); + } + return ret; + } + + public static long stringToLong(String values) { + long value = new BigInteger(values.replaceAll(":", ""), 16).longValue(); + return value; + } + + /** + * This method converts byte array into HexString format with ":" inserted. + */ + public static String bytesToHexStringFormat(byte[] bytes) { + if (bytes == null) { + return "null"; + } + String ret = ""; + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + if (i > 0) { + buf.append(":"); + } + short u8byte = (short) (bytes[i] & 0xff); + String tmp = Integer.toHexString(u8byte); + if (tmp.length() == 1) { + buf.append("0"); + } + buf.append(tmp); + } + ret = buf.toString(); + return ret; + } +} diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDP.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDP.java new file mode 100644 index 0000000000..9b7efbb1e6 --- /dev/null +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDP.java @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.liblldp; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Class that represents the LLDP frame objects + */ + +public class LLDP extends Packet { + private static final String CHASSISID = "ChassisId"; + private static final String SYSTEMNAMEID = "SystemNameID"; + private static final String PORTID = "PortId"; + private static final String TTL = "TTL"; + private static final int LLDPDefaultTlvs = 4; + private static LLDPTLV emptyTLV = new LLDPTLV().setLength((short) 0) + .setType((byte) 0); + public static final byte[] LLDPMulticastMac = { 1, (byte) 0x80, + (byte) 0xc2, 0, 0, (byte) 0xe }; + private Map tlvList; + + /** + * Default constructor that creates the tlvList LinkedHashMap + */ + public LLDP() { + super(); + tlvList = new LinkedHashMap(LLDPDefaultTlvs); + } + + /** + * Constructor that creates the tlvList LinkedHashMap and sets the write + * access for the same + */ + public LLDP(boolean writeAccess) { + super(writeAccess); + tlvList = new LinkedHashMap(LLDPDefaultTlvs); // Mandatory + // TLVs + } + + /** + * @param String + * - description of the type of TLV + * @return byte - type of TLV + */ + private byte getType(String typeDesc) { + if (typeDesc.equals(CHASSISID)) { + return LLDPTLV.TLVType.ChassisID.getValue(); + } else if (typeDesc.equals(PORTID)) { + return LLDPTLV.TLVType.PortID.getValue(); + } else if (typeDesc.equals(TTL)) { + return LLDPTLV.TLVType.TTL.getValue(); + } else { + return LLDPTLV.TLVType.Unknown.getValue(); + } + } + + /** + * @param String + * - description of the type of TLV + * @return LLDPTLV - full TLV + */ + public LLDPTLV getTLV(String type) { + return tlvList.get(getType(type)); + } + + /** + * @param String + * - description of the type of TLV + * @param LLDPTLV + * - tlv to set + * @return void + */ + public void setTLV(String type, LLDPTLV tlv) { + tlvList.put(getType(type), tlv); + } + + /** + * @return the chassisId TLV + */ + public LLDPTLV getChassisId() { + return getTLV(CHASSISID); + } + + /** + * @param LLDPTLV + * - the chassisId to set + */ + public LLDP setChassisId(LLDPTLV chassisId) { + tlvList.put(getType(CHASSISID), chassisId); + return this; + } + + /** + * @return the SystemName TLV + */ + public LLDPTLV getSystemNameId() { + return getTLV(SYSTEMNAMEID); + } + + /** + * @param LLDPTLV + * - the chassisId to set + */ + public LLDP setSystemNameId(LLDPTLV systemNameId) { + tlvList.put(getType(SYSTEMNAMEID), systemNameId); + return this; + } + + /** + * @return LLDPTLV - the portId TLV + */ + public LLDPTLV getPortId() { + return tlvList.get(getType(PORTID)); + } + + /** + * @param LLDPTLV + * - the portId to set + * @return LLDP + */ + public LLDP setPortId(LLDPTLV portId) { + tlvList.put(getType(PORTID), portId); + return this; + } + + /** + * @return LLDPTLV - the ttl TLV + */ + public LLDPTLV getTtl() { + return tlvList.get(getType(TTL)); + } + + /** + * @param LLDPTLV + * - the ttl to set + * @return LLDP + */ + public LLDP setTtl(LLDPTLV ttl) { + tlvList.put(getType(TTL), ttl); + return this; + } + + /** + * @return the optionalTLVList + */ + public List getOptionalTLVList() { + List list = new ArrayList(); + for (Map.Entry entry : tlvList.entrySet()) { + byte type = entry.getKey(); + if ((type == LLDPTLV.TLVType.ChassisID.getValue()) + || (type == LLDPTLV.TLVType.PortID.getValue()) + || (type == LLDPTLV.TLVType.TTL.getValue())) { + continue; + } else { + list.add(entry.getValue()); + } + } + return list; + } + + /** + * @param optionalTLVList + * the optionalTLVList to set + * @return LLDP + */ + public LLDP setOptionalTLVList(List optionalTLVList) { + for (LLDPTLV tlv : optionalTLVList) { + tlvList.put(tlv.getType(), tlv); + } + return this; + } + + @Override + public Packet deserialize(byte[] data, int bitOffset, int size) + throws PacketException { + int lldpOffset = bitOffset; // LLDP start + int lldpSize = size; // LLDP size + + if (logger.isTraceEnabled()) { + logger.trace("LLDP: {} (offset {} bitsize {})", new Object[] { + HexEncode.bytesToHexString(data), lldpOffset, lldpSize }); + } + /* + * Deserialize the TLVs until we reach the end of the packet + */ + while (lldpSize > 0) { + LLDPTLV tlv = new LLDPTLV(); + tlv.deserialize(data, lldpOffset, lldpSize); + if (tlv.getType() == 0 && tlv.getLength() == 0) { + break; + } + int tlvSize = tlv.getTLVSize(); // Size of current TLV in bits + lldpOffset += tlvSize; + lldpSize -= tlvSize; + this.tlvList.put(tlv.getType(), tlv); + } + return this; + } + + @Override + public byte[] serialize() throws PacketException { + int startOffset = 0; + byte[] serializedBytes = new byte[getLLDPPacketLength()]; + + for (Map.Entry entry : tlvList.entrySet()) { + LLDPTLV tlv = entry.getValue(); + int numBits = tlv.getTLVSize(); + try { + BitBufferHelper.setBytes(serializedBytes, tlv.serialize(), + startOffset, numBits); + } catch (BufferException e) { + throw new PacketException(e.getMessage()); + } + startOffset += numBits; + } + // Now add the empty LLDPTLV at the end + try { + BitBufferHelper.setBytes(serializedBytes, + LLDP.emptyTLV.serialize(), startOffset, + LLDP.emptyTLV.getTLVSize()); + } catch (BufferException e) { + throw new PacketException(e.getMessage()); + } + + if (logger.isTraceEnabled()) { + logger.trace("LLDP: serialized: {}", + HexEncode.bytesToHexString(serializedBytes)); + } + return serializedBytes; + } + + /** + * Returns the size of LLDP packet in bytes + * + * @return int - LLDP Packet size in bytes + */ + private int getLLDPPacketLength() { + int len = 0; + LLDPTLV tlv; + + for (Map.Entry entry : this.tlvList.entrySet()) { + tlv = entry.getValue(); + len += tlv.getTLVSize(); + } + len += LLDP.emptyTLV.getTLVSize(); + + return len / NetUtils.NumBitsInAByte; + } +} diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDPTLV.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDPTLV.java new file mode 100644 index 0000000000..22bd4626d1 --- /dev/null +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDPTLV.java @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.liblldp; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.commons.lang3.tuple.Pair; + +/** + * Class that represents the LLDPTLV objects + */ + +public class LLDPTLV extends Packet { + private static final String TYPE = "Type"; + private static final String LENGTH = "Length"; + private static final String VALUE = "Value"; + private static final int LLDPTLVFields = 3; + public static final byte[] OFOUI = new byte[] { (byte) 0x00, (byte) 0x26, + (byte) 0xe1 }; // OpenFlow OUI + public static final byte[] customTlvSubType = new byte[] { 0 }; + public static final int customTlvOffset = OFOUI.length + + customTlvSubType.length; + public static final byte chassisIDSubType[] = new byte[] { 4 }; // MAC address for the system + public static final byte portIDSubType[] = new byte[] { 7 }; // locally assigned + + public enum TLVType { + Unknown((byte) 0), ChassisID((byte) 1), PortID((byte) 2), TTL((byte) 3), PortDesc( + (byte) 4), SystemName((byte) 5), SystemDesc((byte) 6), Custom( + (byte) 127); + + private byte value; + + private TLVType(byte value) { + this.value = value; + } + + public byte getValue() { + return value; + } + } + + private static Map> fieldCoordinates = new LinkedHashMap>() { + private static final long serialVersionUID = 1L; + + { + put(TYPE, new MutablePair(0, 7)); + put(LENGTH, new MutablePair(7, 9)); + put(VALUE, new MutablePair(16, 0)); + } + }; + + protected Map fieldValues; + + /** + * Default constructor that creates and sets the hash map values and sets + * the payload to null + */ + public LLDPTLV() { + payload = null; + fieldValues = new HashMap(LLDPTLVFields); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + } + + /** + * Constructor that writes the passed LLDPTLV values to the hdrFieldsMap + */ + public LLDPTLV(LLDPTLV other) { + for (Map.Entry entry : other.hdrFieldsMap.entrySet()) { + this.hdrFieldsMap.put(entry.getKey(), entry.getValue()); + } + } + + /** + * @return int - the length of TLV + */ + public int getLength() { + return (int) BitBufferHelper.toNumber(fieldValues.get(LENGTH), + fieldCoordinates.get(LENGTH).getRight().intValue()); + } + + /** + * @return byte - the type of TLV + */ + public byte getType() { + return BitBufferHelper.getByte(fieldValues.get(TYPE)); + } + + /** + * @return byte[] - the value field of TLV + */ + public byte[] getValue() { + return fieldValues.get(VALUE); + } + + /** + * @param byte - the type to set + * @return LLDPTLV + */ + public LLDPTLV setType(byte type) { + byte[] lldpTLVtype = { type }; + fieldValues.put(TYPE, lldpTLVtype); + return this; + } + + /** + * @param short - the length to set + * @return LLDPTLV + */ + public LLDPTLV setLength(short length) { + fieldValues.put(LENGTH, BitBufferHelper.toByteArray(length)); + return this; + } + + /** + * @param byte[] - the value to set + * @return LLDPTLV + */ + public LLDPTLV setValue(byte[] value) { + fieldValues.put(VALUE, value); + return this; + } + + @Override + public void setHeaderField(String headerField, byte[] readValue) { + hdrFieldsMap.put(headerField, readValue); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + + ((fieldValues == null) ? 0 : fieldValues.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LLDPTLV other = (LLDPTLV) obj; + if (fieldValues == null) { + if (other.fieldValues != null) { + return false; + } + } else if (!fieldValues.equals(other.fieldValues)) { + return false; + } + return true; + } + + @Override + public int getfieldnumBits(String fieldName) { + if (fieldName.equals(VALUE)) { + return (NetUtils.NumBitsInAByte * BitBufferHelper.getShort( + fieldValues.get(LENGTH), fieldCoordinates.get(LENGTH) + .getRight().intValue())); + } + return fieldCoordinates.get(fieldName).getRight(); + } + + /** + * Returns the size in bits of the whole TLV + * + * @return int - size in bits of full TLV + */ + public int getTLVSize() { + return (LLDPTLV.fieldCoordinates.get(TYPE).getRight() + // static + LLDPTLV.fieldCoordinates.get(LENGTH).getRight() + // static + getfieldnumBits(VALUE)); // variable + } + + /** + * Creates the SystemName TLV value + * + * @param nodeId + * node identifier string + * @return the SystemName TLV value in byte array + */ + static public byte[] createSystemNameTLVValue(String nodeId) { + byte[] nid = nodeId.getBytes(); + return nid; + } + + /** + * Creates the ChassisID TLV value including the subtype and ChassisID + * string + * + * @param nodeId + * node identifier string + * @return the ChassisID TLV value in byte array + */ + static public byte[] createChassisIDTLVValue(String nodeId) { + byte[] nid = HexEncode.bytesFromHexString(nodeId); + byte[] cid = new byte[6]; + int srcPos = 0, dstPos = 0; + + if (nid.length > cid.length) { + srcPos = nid.length - cid.length; + } else { + dstPos = cid.length - nid.length; + } + System.arraycopy(nid, srcPos, cid, dstPos, cid.length); + + byte[] cidValue = new byte[cid.length + chassisIDSubType.length]; + + System.arraycopy(chassisIDSubType, 0, cidValue, 0, + chassisIDSubType.length); + System.arraycopy(cid, 0, cidValue, chassisIDSubType.length, cid.length); + + return cidValue; + } + + /** + * Creates the PortID TLV value including the subtype and PortID string + * + * @param portId + * port identifier string + * @return the PortID TLV value in byte array + */ + static public byte[] createPortIDTLVValue(String portId) { + byte[] pid = portId.getBytes(Charset.defaultCharset()); + byte[] pidValue = new byte[pid.length + portIDSubType.length]; + + System.arraycopy(portIDSubType, 0, pidValue, 0, portIDSubType.length); + System.arraycopy(pid, 0, pidValue, portIDSubType.length, pid.length); + + return pidValue; + } + + /** + * Creates the custom TLV value including OUI, subtype and custom string + * + * @param portId + * port identifier string + * @return the custom TLV value in byte array + */ + static public byte[] createCustomTLVValue(String customString) { + byte[] customArray = customString.getBytes(Charset.defaultCharset()); + byte[] customValue = new byte[customTlvOffset + customArray.length]; + + System.arraycopy(OFOUI, 0, customValue, 0, OFOUI.length); + System.arraycopy(customTlvSubType, 0, customValue, OFOUI.length, + customTlvSubType.length); + System.arraycopy(customArray, 0, customValue, customTlvOffset, + customArray.length); + + return customValue; + } + + /** + * Retrieves the string from TLV value and returns it in HexString format + * + * @param tlvValue + * the TLV value + * @param tlvLen + * the TLV length + * @return the HexString + */ + static public String getHexStringValue(byte[] tlvValue, int tlvLen) { + byte[] cidBytes = new byte[tlvLen - chassisIDSubType.length]; + System.arraycopy(tlvValue, chassisIDSubType.length, cidBytes, 0, + cidBytes.length); + return HexEncode.bytesToHexStringFormat(cidBytes); + } + + /** + * Retrieves the string from TLV value + * + * @param tlvValue + * the TLV value + * @param tlvLen + * the TLV length + * @return the string + */ + static public String getStringValue(byte[] tlvValue, int tlvLen) { + byte[] pidSubType = new byte[portIDSubType.length]; + byte[] pidBytes = new byte[tlvLen - portIDSubType.length]; + System.arraycopy(tlvValue, 0, pidSubType, 0, + pidSubType.length); + System.arraycopy(tlvValue, portIDSubType.length, pidBytes, 0, + pidBytes.length); + if (pidSubType[0] == (byte) 0x3) { + return HexEncode.bytesToHexStringFormat(pidBytes); + } else { + return (new String(pidBytes, Charset.defaultCharset())); + } + } + + /** + * Retrieves the custom string from the Custom TLV value which includes OUI, + * subtype and custom string + * + * @param customTlvValue + * the custom TLV value + * @param customTlvLen + * the custom TLV length + * @return the custom string + */ + static public String getCustomString(byte[] customTlvValue, int customTlvLen) { + String customString = ""; + byte[] vendor = new byte[3]; + System.arraycopy(customTlvValue, 0, vendor, 0, vendor.length); + if (Arrays.equals(vendor, LLDPTLV.OFOUI)) { + int customArrayLength = customTlvLen - customTlvOffset; + byte[] customArray = new byte[customArrayLength]; + System.arraycopy(customTlvValue, customTlvOffset, customArray, 0, + customArrayLength); + try { + customString = new String(customArray, "UTF-8"); + } catch (UnsupportedEncodingException e) { + } + } + + return customString; + } +} diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/NetUtils.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/NetUtils.java new file mode 100644 index 0000000000..0320cf6b47 --- /dev/null +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/NetUtils.java @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2013-2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.liblldp; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class containing the common utility functions needed for operating on + * networking data structures + */ +public abstract class NetUtils { + protected static final Logger logger = LoggerFactory.getLogger(NetUtils.class); + /** + * Constant holding the number of bits in a byte + */ + public static final int NumBitsInAByte = 8; + + /** + * Constant holding the number of bytes in MAC Address + */ + public static final int MACAddrLengthInBytes = 6; + + /** + * Constant holding the number of words in MAC Address + */ + public static final int MACAddrLengthInWords = 3; + + /** + * Constant holding the broadcast MAC address + */ + private static final byte[] BroadcastMACAddr = {-1, -1, -1, -1, -1, -1}; + + /** + * Converts a 4 bytes array into an integer number + * + * @param ba + * the 4 bytes long byte array + * @return the integer number + */ + public static int byteArray4ToInt(byte[] ba) { + if (ba == null || ba.length != 4) { + return 0; + } + return (0xff & ba[0]) << 24 | (0xff & ba[1]) << 16 | (0xff & ba[2]) << 8 | (0xff & ba[3]); + } + + /** + * Converts a 6 bytes array into a long number MAC addresses. + * + * @param ba + * The 6 bytes long byte array. + * @return The long number. + * Zero is returned if {@code ba} is {@code null} or + * the length of it is not six. + */ + public static long byteArray6ToLong(byte[] ba) { + if (ba == null || ba.length != MACAddrLengthInBytes) { + return 0L; + } + long num = 0L; + int i = 0; + do { + num <<= NumBitsInAByte; + num |= 0xff & ba[i]; + i++; + } while (i < MACAddrLengthInBytes); + return num; + } + + /** + * Converts a long number to a 6 bytes array for MAC addresses. + * + * @param addr + * The long number. + * @return The byte array. + */ + public static byte[] longToByteArray6(long addr){ + byte[] mac = new byte[MACAddrLengthInBytes]; + int i = MACAddrLengthInBytes - 1; + do { + mac[i] = (byte) addr; + addr >>>= NumBitsInAByte; + i--; + } while (i >= 0); + return mac; + } + + /** + * Converts an integer number into a 4 bytes array + * + * @param i + * the integer number + * @return the byte array + */ + public static byte[] intToByteArray4(int i) { + return new byte[] { (byte) ((i >> 24) & 0xff), (byte) ((i >> 16) & 0xff), (byte) ((i >> 8) & 0xff), + (byte) (i & 0xff) }; + } + + /** + * Converts an IP address passed as integer value into the respective + * InetAddress object + * + * @param address + * the IP address in integer form + * @return the IP address in InetAddress form + */ + public static InetAddress getInetAddress(int address) { + InetAddress ip = null; + try { + ip = InetAddress.getByAddress(NetUtils.intToByteArray4(address)); + } catch (UnknownHostException e) { + logger.error("", e); + } + return ip; + } + + /** + * Return the InetAddress Network Mask given the length of the prefix bit + * mask. The prefix bit mask indicates the contiguous leading bits that are + * NOT masked out. Example: A prefix bit mask length of 8 will give an + * InetAddress Network Mask of 255.0.0.0 + * + * @param prefixMaskLength + * integer representing the length of the prefix network mask + * @param isV6 + * boolean representing the IP version of the returned address + * @return + */ + public static InetAddress getInetNetworkMask(int prefixMaskLength, boolean isV6) { + if (prefixMaskLength < 0 || (!isV6 && prefixMaskLength > 32) || (isV6 && prefixMaskLength > 128)) { + return null; + } + byte v4Address[] = { 0, 0, 0, 0 }; + byte v6Address[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + byte address[] = (isV6) ? v6Address : v4Address; + int numBytes = prefixMaskLength / 8; + int numBits = prefixMaskLength % 8; + int i = 0; + for (; i < numBytes; i++) { + address[i] = (byte) 0xff; + } + if (numBits > 0) { + int rem = 0; + for (int j = 0; j < numBits; j++) { + rem |= 1 << (7 - j); + } + address[i] = (byte) rem; + } + + try { + return InetAddress.getByAddress(address); + } catch (UnknownHostException e) { + logger.error("", e); + } + return null; + } + + /** + * Returns the prefix size in bits of the specified subnet mask. Example: + * For the subnet mask ff.ff.ff.e0 it returns 25 while for ff.00.00.00 it + * returns 8. If the passed subnetMask array is null, 0 is returned. + * + * @param subnetMask + * the subnet mask as byte array + * @return the prefix length as number of bits + */ + public static int getSubnetMaskLength(byte[] subnetMask) { + int maskLength = 0; + if (subnetMask != null && (subnetMask.length == 4 || subnetMask.length == 16)) { + int index = 0; + while (index < subnetMask.length && subnetMask[index] == (byte) 0xFF) { + maskLength += NetUtils.NumBitsInAByte; + index++; + } + if (index != subnetMask.length) { + int bits = NetUtils.NumBitsInAByte - 1; + while (bits >= 0 && (subnetMask[index] & 1 << bits) != 0) { + bits--; + maskLength++; + } + } + } + return maskLength; + } + + /** + * Returns the prefix size in bits of the specified subnet mask. Example: + * For the subnet mask 255.255.255.128 it returns 25 while for 255.0.0.0 it + * returns 8. If the passed subnetMask object is null, 0 is returned + * + * @param subnetMask + * the subnet mask as InetAddress + * @return the prefix length as number of bits + */ + public static int getSubnetMaskLength(InetAddress subnetMask) { + return subnetMask == null ? 0 : NetUtils.getSubnetMaskLength(subnetMask.getAddress()); + } + + /** + * Given an IP address and a prefix network mask length, it returns the + * equivalent subnet prefix IP address Example: for ip = "172.28.30.254" and + * maskLen = 25 it will return "172.28.30.128" + * + * @param ip + * the IP address in InetAddress form + * @param maskLen + * the length of the prefix network mask + * @return the subnet prefix IP address in InetAddress form + */ + public static InetAddress getSubnetPrefix(InetAddress ip, int maskLen) { + int bytes = maskLen / 8; + int bits = maskLen % 8; + byte modifiedByte; + byte[] sn = ip.getAddress(); + if (bits > 0) { + modifiedByte = (byte) (sn[bytes] >> (8 - bits)); + sn[bytes] = (byte) (modifiedByte << (8 - bits)); + bytes++; + } + for (; bytes < sn.length; bytes++) { + sn[bytes] = (byte) (0); + } + try { + return InetAddress.getByAddress(sn); + } catch (UnknownHostException e) { + return null; + } + } + + /** + * Checks if the test address and mask conflicts with the filter address and + * mask + * + * For example: + * testAddress: 172.28.2.23 + * testMask: 255.255.255.0 + * filterAddress: 172.28.1.10 + * testMask: 255.255.255.0 + * do conflict + * + * testAddress: 172.28.2.23 + * testMask: 255.255.255.0 + * filterAddress: 172.28.1.10 + * testMask: 255.255.0.0 + * do not conflict + * + * Null parameters are permitted + * + * @param testAddress + * @param filterAddress + * @param testMask + * @param filterMask + * @return + */ + public static boolean inetAddressConflict(InetAddress testAddress, InetAddress filterAddress, InetAddress testMask, + InetAddress filterMask) { + // Sanity check + if ((testAddress == null) || (filterAddress == null)) { + return false; + } + + // Presence check + if (isAny(testAddress) || isAny(filterAddress)) { + return false; + } + + int testMaskLen = (testMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils + .getSubnetMaskLength(testMask); + int filterMaskLen = (filterMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils + .getSubnetMaskLength(filterMask); + + // Mask length check. Test mask has to be more specific than filter one + if (testMaskLen < filterMaskLen) { + return true; + } + + // Subnet Prefix on filter mask length must be the same + InetAddress prefix1 = getSubnetPrefix(testAddress, filterMaskLen); + InetAddress prefix2 = getSubnetPrefix(filterAddress, filterMaskLen); + return (!prefix1.equals(prefix2)); + } + + /** + * Returns true if the passed MAC address is all zero + * + * @param mac + * the byte array representing the MAC address + * @return true if all MAC bytes are zero + */ + public static boolean isZeroMAC(byte[] mac) { + for (short i = 0; i < 6; i++) { + if (mac[i] != 0) { + return false; + } + } + return true; + } + + /** + * Returns true if the MAC address is the broadcast MAC address and false + * otherwise. + * + * @param MACAddress + * @return + */ + public static boolean isBroadcastMACAddr(byte[] MACAddress) { + if (MACAddress.length == MACAddrLengthInBytes) { + for (int i = 0; i < 6; i++) { + if (MACAddress[i] != BroadcastMACAddr[i]) { + return false; + } + } + return true; + } + + return false; + } + /** + * Returns true if the MAC address is a unicast MAC address and false + * otherwise. + * + * @param MACAddress + * @return + */ + public static boolean isUnicastMACAddr(byte[] MACAddress) { + if (MACAddress.length == MACAddrLengthInBytes) { + return (MACAddress[0] & 1) == 0; + } + return false; + } + + /** + * Returns true if the MAC address is a multicast MAC address and false + * otherwise. Note that this explicitly returns false for the broadcast MAC + * address. + * + * @param MACAddress + * @return + */ + public static boolean isMulticastMACAddr(byte[] MACAddress) { + if (MACAddress.length == MACAddrLengthInBytes && !isBroadcastMACAddr(MACAddress)) { + return (MACAddress[0] & 1) != 0; + } + return false; + } + + /** + * Returns true if the passed InetAddress contains all zero + * + * @param ip + * the IP address to test + * @return true if the address is all zero + */ + public static boolean isAny(InetAddress ip) { + for (byte b : ip.getAddress()) { + if (b != 0) { + return false; + } + } + return true; + } + + public static boolean fieldsConflict(int field1, int field2) { + if ((field1 == 0) || (field2 == 0) || (field1 == field2)) { + return false; + } + return true; + } + + public static InetAddress parseInetAddress(String addressString) { + InetAddress address = null; + try { + address = InetAddress.getByName(addressString); + } catch (UnknownHostException e) { + logger.error("", e); + } + return address; + } + + /** + * Checks if the passed IP v4 address in string form is valid The address + * may specify a mask at the end as "/MM" + * + * @param cidr + * the v4 address as A.B.C.D/MM + * @return + */ + public static boolean isIPv4AddressValid(String cidr) { + if (cidr == null) { + return false; + } + + String values[] = cidr.split("/"); + Pattern ipv4Pattern = Pattern + .compile("(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])"); + Matcher mm = ipv4Pattern.matcher(values[0]); + if (!mm.matches()) { + return false; + } + if (values.length >= 2) { + int prefix = Integer.valueOf(values[1]); + if ((prefix < 0) || (prefix > 32)) { + return false; + } + } + return true; + } + + /** + * Checks if the passed IP v6 address in string form is valid The address + * may specify a mask at the end as "/MMM" + * + * @param cidr + * the v6 address as A::1/MMM + * @return + */ + public static boolean isIPv6AddressValid(String cidr) { + if (cidr == null) { + return false; + } + + String values[] = cidr.split("/"); + try { + // when given an IP address, InetAddress.getByName validates the ip + // address + InetAddress addr = InetAddress.getByName(values[0]); + if (!(addr instanceof Inet6Address)) { + return false; + } + } catch (UnknownHostException ex) { + return false; + } + + if (values.length >= 2) { + int prefix = Integer.valueOf(values[1]); + if ((prefix < 0) || (prefix > 128)) { + return false; + } + } + return true; + } + + /** + * Checks if the passed IP address in string form is a valid v4 or v6 + * address. The address may specify a mask at the end as "/MMM" + * + * @param cidr + * the v4 or v6 address as IP/MMM + * @return + */ + public static boolean isIPAddressValid(String cidr) { + return NetUtils.isIPv4AddressValid(cidr) || NetUtils.isIPv6AddressValid(cidr); + } + + /* + * Following utilities are useful when you need to compare or bit shift java + * primitive type variable which are inherently signed + */ + /** + * Returns the unsigned value of the passed byte variable + * + * @param b + * the byte value + * @return the int variable containing the unsigned byte value + */ + public static int getUnsignedByte(byte b) { + return b & 0xFF; + } + + /** + * Return the unsigned value of the passed short variable + * + * @param s + * the short value + * @return the int variable containing the unsigned short value + */ + public static int getUnsignedShort(short s) { + return s & 0xFFFF; + } + + /** + * Returns the highest v4 or v6 InetAddress + * + * @param v6 + * true for IPv6, false for Ipv4 + * @return The highest IPv4 or IPv6 address + */ + public static InetAddress gethighestIP(boolean v6) { + try { + return (v6) ? InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") : InetAddress + .getByName("255.255.255.255"); + } catch (UnknownHostException e) { + return null; + } + } + + /** + * Returns Broadcast MAC Address + * + * @return the byte array containing broadcast mac address + */ + public static byte[] getBroadcastMACAddr() { + return Arrays.copyOf(BroadcastMACAddr, BroadcastMACAddr.length); + } +} diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Packet.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Packet.java new file mode 100644 index 0000000000..2af185221c --- /dev/null +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Packet.java @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2013-2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.liblldp; + +import java.util.Arrays; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Abstract class which represents the generic network packet object It provides + * the basic methods which are common for all the packets, like serialize and + * deserialize + */ + +public abstract class Packet { + protected static final Logger logger = LoggerFactory + .getLogger(Packet.class); + // Access level granted to this packet + protected boolean writeAccess; + // When deserialized from wire, packet could result corrupted + protected boolean corrupted; + // The packet that encapsulate this packet + protected Packet parent; + // The packet encapsulated by this packet + protected Packet payload; + // The unparsed raw payload carried by this packet + protected byte[] rawPayload; + // Bit coordinates of packet header fields + protected Map> hdrFieldCoordMap; + // Header fields values: Map + protected Map hdrFieldsMap; + // The class of the encapsulated packet object + protected Class payloadClass; + + public Packet() { + writeAccess = false; + corrupted = false; + } + + public Packet(boolean writeAccess) { + this.writeAccess = writeAccess; + corrupted = false; + } + + public Packet getParent() { + return parent; + } + + public Packet getPayload() { + return payload; + } + + public void setParent(Packet parent) { + this.parent = parent; + } + + public void setPayload(Packet payload) { + this.payload = payload; + } + + public void setHeaderField(String headerField, byte[] readValue) { + hdrFieldsMap.put(headerField, readValue); + } + + /** + * This method deserializes the data bits obtained from the wire into the + * respective header and payload which are of type Packet + * + * @param byte[] data - data from wire to deserialize + * @param int bitOffset bit position where packet header starts in data + * array + * @param int size of packet in bits + * @return Packet + * @throws PacketException + */ + public Packet deserialize(byte[] data, int bitOffset, int size) + throws PacketException { + + // Deserialize the header fields one by one + int startOffset = 0, numBits = 0; + for (Entry> pairs : hdrFieldCoordMap + .entrySet()) { + String hdrField = pairs.getKey(); + startOffset = bitOffset + this.getfieldOffset(hdrField); + numBits = this.getfieldnumBits(hdrField); + + byte[] hdrFieldBytes = null; + try { + hdrFieldBytes = BitBufferHelper.getBits(data, startOffset, + numBits); + } catch (BufferException e) { + throw new PacketException(e.getMessage()); + } + + /* + * Store the raw read value, checks the payload type and set the + * payloadClass accordingly + */ + this.setHeaderField(hdrField, hdrFieldBytes); + + if (logger.isTraceEnabled()) { + logger.trace("{}: {}: {} (offset {} bitsize {})", + new Object[] { this.getClass().getSimpleName(), hdrField, + HexEncode.bytesToHexString(hdrFieldBytes), + startOffset, numBits }); + } + } + + // Deserialize the payload now + int payloadStart = startOffset + numBits; + int payloadSize = data.length * NetUtils.NumBitsInAByte - payloadStart; + + if (payloadClass != null) { + try { + payload = payloadClass.newInstance(); + } catch (Exception e) { + throw new RuntimeException( + "Error parsing payload for Ethernet packet", e); + } + payload.deserialize(data, payloadStart, payloadSize); + payload.setParent(this); + } else { + /* + * The payload class was not set, it means no class for parsing + * this payload is present. Let's store the raw payload if any. + */ + int start = payloadStart / NetUtils.NumBitsInAByte; + int stop = start + payloadSize / NetUtils.NumBitsInAByte; + rawPayload = Arrays.copyOfRange(data, start, stop); + } + + + // Take care of computation that can be done only after deserialization + postDeserializeCustomOperation(data, payloadStart - getHeaderSize()); + + return this; + } + + /** + * This method serializes the header and payload from the respective + * packet class, into a single stream of bytes to be sent on the wire + * + * @return The byte array representing the serialized Packet + * @throws PacketException + */ + public byte[] serialize() throws PacketException { + + // Acquire or compute the serialized payload + byte[] payloadBytes = null; + if (payload != null) { + payloadBytes = payload.serialize(); + } else if (rawPayload != null) { + payloadBytes = rawPayload; + } + int payloadSize = (payloadBytes == null) ? 0 : payloadBytes.length; + + // Allocate the buffer to contain the full (header + payload) packet + int headerSize = this.getHeaderSize() / NetUtils.NumBitsInAByte; + byte packetBytes[] = new byte[headerSize + payloadSize]; + if (payloadBytes != null) { + System.arraycopy(payloadBytes, 0, packetBytes, headerSize, payloadSize); + } + + // Serialize this packet header, field by field + for (Map.Entry> pairs : hdrFieldCoordMap + .entrySet()) { + String field = pairs.getKey(); + byte[] fieldBytes = hdrFieldsMap.get(field); + // Let's skip optional fields when not set + if (fieldBytes != null) { + try { + BitBufferHelper.setBytes(packetBytes, fieldBytes, + getfieldOffset(field), getfieldnumBits(field)); + } catch (BufferException e) { + throw new PacketException(e.getMessage()); + } + } + } + + // Perform post serialize operations (like checksum computation) + postSerializeCustomOperation(packetBytes); + + if (logger.isTraceEnabled()) { + logger.trace("{}: {}", this.getClass().getSimpleName(), + HexEncode.bytesToHexString(packetBytes)); + } + + return packetBytes; + } + + /** + * This method gets called at the end of the serialization process It is + * intended for the child packets to insert some custom data into the output + * byte stream which cannot be done or cannot be done efficiently during the + * normal Packet.serialize() path. An example is the checksum computation + * for IPv4 + * + * @param byte[] - serialized bytes + * @throws PacketException + */ + protected void postSerializeCustomOperation(byte[] myBytes) + throws PacketException { + // no op + } + + /** + * This method re-computes the checksum of the bits received on the wire and + * validates it with the checksum in the bits received Since the computation + * of checksum varies based on the protocol, this method is overridden. + * Currently only IPv4 and ICMP do checksum computation and validation. TCP + * and UDP need to implement these if required. + * + * @param byte[] data The byte stream representing the Ethernet frame + * @param int startBitOffset The bit offset from where the byte array corresponding to this Packet starts in the frame + * @throws PacketException + */ + protected void postDeserializeCustomOperation(byte[] data, int startBitOffset) + throws PacketException { + // no op + } + + /** + * Gets the header length in bits + * + * @return int the header length in bits + */ + public int getHeaderSize() { + int size = 0; + /* + * We need to iterate over the fields that were read in the frame + * (hdrFieldsMap) not all the possible ones described in + * hdrFieldCoordMap. For ex, 802.1Q may or may not be there + */ + for (Map.Entry fieldEntry : hdrFieldsMap.entrySet()) { + if (fieldEntry.getValue() != null) { + String field = fieldEntry.getKey(); + size += getfieldnumBits(field); + } + } + return size; + } + + /** + * This method fetches the start bit offset for header field specified by + * 'fieldname'. The offset is present in the hdrFieldCoordMap of the + * respective packet class + * + * @param String + * fieldName + * @return Integer - startOffset of the requested field + */ + public int getfieldOffset(String fieldName) { + return hdrFieldCoordMap.get(fieldName).getLeft(); + } + + /** + * This method fetches the number of bits for header field specified by + * 'fieldname'. The numBits are present in the hdrFieldCoordMap of the + * respective packet class + * + * @param String + * fieldName + * @return Integer - number of bits of the requested field + */ + public int getfieldnumBits(String fieldName) { + return hdrFieldCoordMap.get(fieldName).getRight(); + } + + @Override + public String toString() { + StringBuilder ret = new StringBuilder(); + ret.append(this.getClass().getSimpleName()); + ret.append(": ["); + for (String field : hdrFieldCoordMap.keySet()) { + byte[] value = hdrFieldsMap.get(field); + ret.append(field); + ret.append(": "); + ret.append(HexEncode.bytesToHexString(value)); + ret.append(", "); + } + ret.replace(ret.length()-2, ret.length()-1, "]"); + return ret.toString(); + } + + /** + * Returns the raw payload carried by this packet in case payload was not + * parsed. Caller can call this function in case the getPaylod() returns null. + * + * @return The raw payload if not parsable as an array of bytes, null otherwise + */ + public byte[] getRawPayload() { + return rawPayload; + } + + /** + * Set a raw payload in the packet class + * + * @param payload The raw payload as byte array + */ + public void setRawPayload(byte[] payload) { + this.rawPayload = Arrays.copyOf(payload, payload.length); + } + + /** + * Return whether the deserialized packet is to be considered corrupted. + * This is the case when the checksum computed after reconstructing the + * packet received from wire is not equal to the checksum read from the + * stream. For the Packet class which do not have a checksum field, this + * function will always return false. + * + * + * @return true if the deserialized packet's recomputed checksum is not + * equal to the packet carried checksum + */ + public boolean isCorrupted() { + return corrupted; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + + ((this.hdrFieldsMap == null) ? 0 : hdrFieldsMap.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (getClass() != obj.getClass()) { + return false; + } + Packet other = (Packet) obj; + if (hdrFieldsMap == other.hdrFieldsMap) { + return true; + } + if (hdrFieldsMap == null || other.hdrFieldsMap == null) { + return false; + } + if (hdrFieldsMap != null && other.hdrFieldsMap != null) { + for (String field : hdrFieldsMap.keySet()) { + if (!Arrays.equals(hdrFieldsMap.get(field), other.hdrFieldsMap.get(field))) { + return false; + } + } + } else { + return false; + } + return true; + } +} diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/PacketException.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/PacketException.java new file mode 100644 index 0000000000..c69fc03e91 --- /dev/null +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/PacketException.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.liblldp; + +/** + * Describes an exception that is raised when the process of serializing or + * deserializing a network packet/stream fails. This generally happens when the + * packet/stream is malformed. + * + */ +public class PacketException extends Exception { + private static final long serialVersionUID = 1L; + + public PacketException(String message) { + super(message); + } +} diff --git a/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/BitBufferHelperTest.java b/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/BitBufferHelperTest.java new file mode 100644 index 0000000000..07fbf0599b --- /dev/null +++ b/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/BitBufferHelperTest.java @@ -0,0 +1,693 @@ + +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.sal.packet; + +import junit.framework.Assert; + +import org.junit.Test; +import org.opendaylight.controller.liblldp.BitBufferHelper; + +public class BitBufferHelperTest { + + @Test + public void testGetByte() { + byte[] data = { 100 }; + Assert.assertTrue(BitBufferHelper.getByte(data) == 100); + } + + @Test + public void testGetBits() throws Exception { + byte[] data = { 10, 12, 14, 20, 55, 69, 82, 97, 109, 117, 127, -50 }; + byte[] bits; + + bits = BitBufferHelper.getBits(data, 88, 8); //BYTE extraOffsetBits = extranumBits = 0 + Assert.assertTrue(bits[0] == -50); + + bits = BitBufferHelper.getBits(data, 8, 16); //Short + Assert.assertTrue(bits[0] == 12); + Assert.assertTrue(bits[1] == 14); + + bits = BitBufferHelper.getBits(data, 32, 32); //Int + Assert.assertTrue(bits[0] == 55); + Assert.assertTrue(bits[1] == 69); + Assert.assertTrue(bits[2] == 82); + Assert.assertTrue(bits[3] == 97); + + bits = BitBufferHelper.getBits(data, 16, 48); //Long + Assert.assertTrue(bits[0] == 14); + Assert.assertTrue(bits[1] == 20); + Assert.assertTrue(bits[2] == 55); + Assert.assertTrue(bits[3] == 69); + Assert.assertTrue(bits[4] == 82); + Assert.assertTrue(bits[5] == 97); + + bits = BitBufferHelper.getBits(data, 40, 7); //BYTE extraOffsetBits = extranumBits != 0 + Assert.assertTrue(bits[0] == 34); + + bits = BitBufferHelper.getBits(data, 8, 13); //Short + Assert.assertTrue(bits[0] == 1); + Assert.assertTrue(bits[1] == -127); + + bits = BitBufferHelper.getBits(data, 32, 28); //Int + Assert.assertTrue(bits[0] == 3); + Assert.assertTrue(bits[1] == 116); + Assert.assertTrue(bits[2] == 85); + Assert.assertTrue(bits[3] == 38); + + bits = BitBufferHelper.getBits(data, 16, 41); //Long + Assert.assertTrue(bits[0] == 0); + Assert.assertTrue(bits[1] == 28); + Assert.assertTrue(bits[2] == 40); + Assert.assertTrue(bits[3] == 110); + Assert.assertTrue(bits[4] == -118); + Assert.assertTrue(bits[5] == -92); + + bits = BitBufferHelper.getBits(data, 3, 7); //BYTE extraOffsetBits != 0; extranumBits == 0 + Assert.assertTrue(bits[0] == 40); + + bits = BitBufferHelper.getBits(data, 13, 16); //Short + Assert.assertTrue(bits[0] == -127); + Assert.assertTrue(bits[1] == -62); + + bits = BitBufferHelper.getBits(data, 5, 32); //Int + Assert.assertTrue(bits[0] == 65); + Assert.assertTrue(bits[1] == -127); + Assert.assertTrue(bits[2] == -62); + Assert.assertTrue(bits[3] == -122); + + bits = BitBufferHelper.getBits(data, 23, 48); //Long + Assert.assertTrue(bits[0] == 10); + Assert.assertTrue(bits[1] == 27); + Assert.assertTrue(bits[2] == -94); + Assert.assertTrue(bits[3] == -87); + Assert.assertTrue(bits[4] == 48); + Assert.assertTrue(bits[5] == -74); + + bits = BitBufferHelper.getBits(data, 66, 9); //BYTE extraOffsetBits != 0; extranumBits != 0 + Assert.assertTrue(bits[0] == 1); + Assert.assertTrue(bits[1] == 107); + + bits = BitBufferHelper.getBits(data, 13, 15); //Short + Assert.assertTrue(bits[0] == 64); + Assert.assertTrue(bits[1] == -31); + + bits = BitBufferHelper.getBits(data, 5, 29); //Int + Assert.assertTrue(bits[0] == 8); + Assert.assertTrue(bits[1] == 48); + Assert.assertTrue(bits[2] == 56); + Assert.assertTrue(bits[3] == 80); + + bits = BitBufferHelper.getBits(data, 31, 43); //Long + Assert.assertTrue(bits[0] == 0); + Assert.assertTrue(bits[1] == -35); + Assert.assertTrue(bits[2] == 21); + Assert.assertTrue(bits[3] == 73); + Assert.assertTrue(bits[4] == -123); + Assert.assertTrue(bits[5] == -75); + + bits = BitBufferHelper.getBits(data, 4, 12); //Short + Assert.assertTrue(bits[0] == 10); + Assert.assertTrue(bits[1] == 12); + + byte[] data1 = { 0, 8 }; + bits = BitBufferHelper.getBits(data1, 7, 9); //Short + Assert.assertTrue(bits[0] == 0); + Assert.assertTrue(bits[1] == 8); + + byte[] data2 = { 2, 8 }; + bits = BitBufferHelper.getBits(data2, 0, 7); //Short + Assert.assertTrue(bits[0] == 1); + + bits = BitBufferHelper.getBits(data2, 7, 9); //Short + Assert.assertTrue(bits[0] == 0); + Assert.assertTrue(bits[1] == 8); + } + + // [01101100][01100000] + // [01100011] + @Test + public void testGetBytes() throws Exception { + byte data[] = { 108, 96, 125, -112, 5, 6, 108, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22 }; + byte[] x; + + Assert.assertTrue(BitBufferHelper.getBits(data, 0, 8)[0] == 108); + Assert.assertTrue(BitBufferHelper.getBits(data, 8, 8)[0] == 96); + + x = BitBufferHelper.getBits(data, 0, 10); + Assert.assertTrue(x[0] == 1); + Assert.assertTrue(x[1] == -79); + + x = BitBufferHelper.getBits(data, 3, 8); + Assert.assertTrue(x[0] == 99); + //Assert.assertTrue(x[1] == 97); + + } + + @Test + public void testMSBMask() { + int numBits = 1; //MSB + int mask = BitBufferHelper.getMSBMask(numBits); + Assert.assertTrue(mask == 128); + + numBits = 8; + mask = BitBufferHelper.getMSBMask(numBits); + Assert.assertTrue(mask == 255); + + numBits = 2; + mask = BitBufferHelper.getMSBMask(numBits); + Assert.assertTrue(mask == 192); + } + + @Test + public void testLSBMask() { + int numBits = 1; //LSB + int mask = BitBufferHelper.getLSBMask(numBits); + Assert.assertTrue(mask == 1); + + numBits = 3; + mask = BitBufferHelper.getLSBMask(numBits); + Assert.assertTrue(mask == 7); + + numBits = 8; + mask = BitBufferHelper.getLSBMask(numBits); + Assert.assertTrue(mask == 255); + } + + @Test + public void testToByteArray() { + short sh = Short.MAX_VALUE; + byte[] data_sh = new byte[Byte.SIZE / 8]; + data_sh = BitBufferHelper.toByteArray(sh); + Assert.assertTrue(data_sh[0] == 127); + Assert.assertTrue(data_sh[1] == -1); + + short sh2 = Short.MIN_VALUE; + byte[] data_sh2 = new byte[Byte.SIZE / 8]; + data_sh2 = BitBufferHelper.toByteArray(sh2); + Assert.assertTrue(data_sh2[0] == -128); + Assert.assertTrue(data_sh2[1] == 0); + + short sh3 = 16384; + byte[] data_sh3 = new byte[Byte.SIZE / 8]; + data_sh3 = BitBufferHelper.toByteArray(sh3); + Assert.assertTrue(data_sh3[0] == 64); + Assert.assertTrue(data_sh3[1] == 0); + + short sh4 = 146; //TCP headerlenflags - startoffset = 103 + byte[] data_sh4 = new byte[Byte.SIZE / 8]; + data_sh4 = BitBufferHelper.toByteArray(sh4); + Assert.assertTrue(data_sh4[0] == 0); + Assert.assertTrue(data_sh4[1] == -110); + + short sh4_2 = 5000; //IPv4 Offset - startOffset = 51 (to 63) + byte[] data_sh4_2 = new byte[Byte.SIZE / 8]; + data_sh4_2 = BitBufferHelper.toByteArray(sh4_2); + Assert.assertTrue(data_sh4_2[0] == 19); + Assert.assertTrue(data_sh4_2[1] == -120); + + short sh4_3 = 5312; //numEndRestBits < numBitstoShiftBy + byte[] data_sh4_3 = new byte[Byte.SIZE / 8]; + data_sh4_3 = BitBufferHelper.toByteArray(sh4_3); + Assert.assertTrue(data_sh4_3[0] == 20); + Assert.assertTrue(data_sh4_3[1] == -64); + + int Int = Integer.MAX_VALUE; + byte[] data_Int = new byte[Integer.SIZE / 8]; + data_Int = BitBufferHelper.toByteArray(Int); + Assert.assertTrue(data_Int[0] == 127); + Assert.assertTrue(data_Int[1] == -1); + Assert.assertTrue(data_Int[2] == -1); + Assert.assertTrue(data_Int[3] == -1); + + int Int2 = Integer.MIN_VALUE; + byte[] data_Int2 = new byte[Integer.SIZE / 8]; + data_Int2 = BitBufferHelper.toByteArray(Int2); + Assert.assertTrue(data_Int2[0] == -128); + Assert.assertTrue(data_Int2[1] == 0); + Assert.assertTrue(data_Int2[2] == 0); + Assert.assertTrue(data_Int2[3] == 0); + + int Int3 = 1077952576; + byte[] data_Int3 = new byte[Integer.SIZE / 8]; + data_Int3 = BitBufferHelper.toByteArray(Int3); + Assert.assertTrue(data_Int3[0] == 64); + Assert.assertTrue(data_Int3[1] == 64); + Assert.assertTrue(data_Int3[2] == 64); + Assert.assertTrue(data_Int3[3] == 64); + + long Lng = Long.MAX_VALUE; + byte[] data_lng = new byte[Long.SIZE / 8]; + data_lng = BitBufferHelper.toByteArray(Lng); + Assert.assertTrue(data_lng[0] == 127); + Assert.assertTrue(data_lng[1] == -1); + Assert.assertTrue(data_lng[2] == -1); + Assert.assertTrue(data_lng[3] == -1); + Assert.assertTrue(data_lng[4] == -1); + Assert.assertTrue(data_lng[5] == -1); + Assert.assertTrue(data_lng[6] == -1); + Assert.assertTrue(data_lng[7] == -1); + + long Lng2 = Long.MIN_VALUE; + byte[] data_lng2 = new byte[Long.SIZE / 8]; + data_lng2 = BitBufferHelper.toByteArray(Lng2); + Assert.assertTrue(data_lng2[0] == -128); + Assert.assertTrue(data_lng2[1] == 0); + Assert.assertTrue(data_lng2[2] == 0); + Assert.assertTrue(data_lng2[3] == 0); + Assert.assertTrue(data_lng2[4] == 0); + Assert.assertTrue(data_lng2[5] == 0); + Assert.assertTrue(data_lng2[6] == 0); + Assert.assertTrue(data_lng2[7] == 0); + + byte B = Byte.MAX_VALUE; + byte[] data_B = new byte[Byte.SIZE / 8]; + data_B = BitBufferHelper.toByteArray(B); + Assert.assertTrue(data_B[0] == 127); + + byte B1 = Byte.MIN_VALUE; + byte[] data_B1 = new byte[Byte.SIZE / 8]; + data_B1 = BitBufferHelper.toByteArray(B1); + Assert.assertTrue(data_B1[0] == -128); + + byte B2 = 64; + byte[] data_B2 = new byte[Byte.SIZE / 8]; + data_B2 = BitBufferHelper.toByteArray(B2); + Assert.assertTrue(data_B2[0] == 64); + + byte B3 = 32; + byte[] data_B3 = new byte[Byte.SIZE / 8]; + data_B3 = BitBufferHelper.toByteArray(B3); + Assert.assertTrue(data_B3[0] == 32); + + } + + @Test + public void testToByteArrayVariable() { + int len = 9; + byte[] data_sh; + data_sh = BitBufferHelper.toByteArray(511, len); + Assert.assertTrue(data_sh[0] == (byte) 255); + Assert.assertTrue(data_sh[1] == (byte) 128); + + data_sh = BitBufferHelper.toByteArray((int) 511, len); + Assert.assertTrue(data_sh[0] == (byte) 255); + Assert.assertTrue(data_sh[1] == (byte) 128); + + data_sh = BitBufferHelper.toByteArray((long) 511, len); + Assert.assertTrue(data_sh[0] == (byte) 255); + Assert.assertTrue(data_sh[1] == (byte) 128); + } + + @Test + public void testToInt() { + byte data[] = { 1 }; + Assert.assertTrue(BitBufferHelper.toNumber(data) == 1); + + byte data2[] = { 1, 1 }; + Assert.assertTrue(BitBufferHelper.toNumber(data2) == 257); + + byte data3[] = { 1, 1, 1 }; + Assert.assertTrue(BitBufferHelper.toNumber(data3) == 65793); + } + + @Test + public void testToLongGetter() { + byte data[] = { 1, 1 }; + Assert.assertTrue(BitBufferHelper.getLong(data) == 257L); + } + + @Test + public void testSetByte() throws Exception { + byte input; + byte[] data = new byte[20]; + + input = 125; + BitBufferHelper.setByte(data, input, 0, Byte.SIZE); + Assert.assertTrue(data[0] == 125); + + input = 109; + BitBufferHelper.setByte(data, input, 152, Byte.SIZE); + Assert.assertTrue(data[19] == 109); + } + + @Test + public void testSetBytes() throws Exception { + byte[] input = { 0, 1 }; + byte[] data = { 6, 0 }; + + BitBufferHelper.setBytes(data, input, 7, 9); + Assert.assertTrue(data[0] == 6); + Assert.assertTrue(data[1] == 1); + } + + //@Test + //INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]*/ + public void testInsertBits() throws Exception { + //CASE 1: startOffset%8 == 0 && numBits%8 == 0 + byte inputdata[] = { 75, 110, 107, 80, 10, 12, 35, 100, 125, 65 }; + int startOffset = 0; + int numBits = 8; + + byte data1[] = new byte[2]; + startOffset = 0; + numBits = 16; + BitBufferHelper.insertBits(data1, inputdata, startOffset, numBits); + Assert.assertTrue(data1[0] == 75); + Assert.assertTrue(data1[1] == 110); + + byte data2[] = new byte[4]; + startOffset = 0; + numBits = 32; + BitBufferHelper.insertBits(data2, inputdata, startOffset, numBits); + Assert.assertTrue(data2[0] == 75); + Assert.assertTrue(data2[1] == 110); + Assert.assertTrue(data2[2] == 107); + Assert.assertTrue(data2[3] == 80); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] // OUTPUT: [01001011] [01101000] = {75, 104} + byte data10[] = new byte[2]; + startOffset = 0; + numBits = 13; + BitBufferHelper.insertBits(data10, inputdata, startOffset, numBits); + Assert.assertTrue(data10[0] == 75); + Assert.assertTrue(data10[1] == 104); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] // OUTPUT: [01001000] = {72} + byte data11[] = new byte[4]; + startOffset = 8; + numBits = 6; + BitBufferHelper.insertBits(data11, inputdata, startOffset, numBits); + Assert.assertTrue(data11[1] == 72); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [01001011] [01101110] [01101000] = {75, 110, 105} + byte data12[] = new byte[4]; + startOffset = 0; + numBits = 23; + BitBufferHelper.insertBits(data12, inputdata, startOffset, numBits); + Assert.assertTrue(data12[0] == 75); + Assert.assertTrue(data12[1] == 110); + Assert.assertTrue(data12[2] == 106); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [01001011] [01101110] [01100000] = {75, 110, 96} + byte data13[] = new byte[4]; + startOffset = 8; + numBits = 20; + BitBufferHelper.insertBits(data13, inputdata, startOffset, numBits); + Assert.assertTrue(data13[1] == 75); + Assert.assertTrue(data13[2] == 110); + Assert.assertTrue(data13[3] == 96); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [01001011] [01101110] [01101011] [10100000]= {75, 110, 107, 80} + byte data14[] = new byte[4]; + startOffset = 0; + numBits = 30; + BitBufferHelper.insertBits(data14, inputdata, startOffset, numBits); + Assert.assertTrue(data14[0] == 75); + Assert.assertTrue(data14[1] == 110); + Assert.assertTrue(data14[2] == 107); + Assert.assertTrue(data14[3] == 80); + + //CASE 3: startOffset%8 != 0, numBits%8 = 0 + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00001001] [11000000] = {72, 96} + byte data16[] = new byte[5]; + startOffset = 3; + numBits = 8; + BitBufferHelper.insertBits(data16, inputdata, startOffset, numBits); + Assert.assertTrue(data16[0] == 9); + Assert.assertTrue(data16[1] == 96); + Assert.assertTrue(data16[2] == 0); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96} + // OUTPUT: [00000100] [1011 0110] [1110 0000] = {4, -54, -96} + + startOffset = 3; + numBits = 16; + byte data17[] = new byte[5]; + BitBufferHelper.insertBits(data17, inputdata, startOffset, numBits); + Assert.assertTrue(data17[0] == 9); + Assert.assertTrue(data17[1] == 109); + Assert.assertTrue(data17[2] == -64); + Assert.assertTrue(data17[3] == 0); + + // INPUT: {79, 110, 111} + // = [01001111] [01101110] [01101111] + //OUTPUT: [0000 1001] [1110 1101] [110 00000] = {9, -19, -64} + byte data18[] = new byte[5]; + byte inputdata3[] = { 79, 110, 111 }; + startOffset = 3; + numBits = 16; + BitBufferHelper.insertBits(data18, inputdata3, startOffset, numBits); + Assert.assertTrue(data18[0] == 9); + Assert.assertTrue(data18[1] == -19); + Assert.assertTrue(data18[2] == -64); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96} + // OUTPUT: [0000 1001] [0110 1101] [1100 1101] [0110 1010] [0000 0001] = {9, 109, -51, 106, 0} + + startOffset = 3; + numBits = 32; + byte data19[] = new byte[5]; + BitBufferHelper.insertBits(data19, inputdata, startOffset, numBits); + Assert.assertTrue(data19[0] == 9); + Assert.assertTrue(data19[1] == 109); + Assert.assertTrue(data19[2] == -51); + Assert.assertTrue(data19[3] == 106); + Assert.assertTrue(data19[4] == 0); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96} + // OUTPUT: data[4, 5, 6] = [0 010 0101] [1 011 0111] [0 000 0000] = {37, -73, 0} + startOffset = 33; + numBits = 16; + byte data20[] = new byte[7]; + BitBufferHelper.insertBits(data20, inputdata, startOffset, numBits); + Assert.assertTrue(data20[4] == 37); + Assert.assertTrue(data20[5] == -73); + Assert.assertTrue(data20[6] == 0); + + //CASE 4: extranumBits != 0 AND extraOffsetBits != 0 + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96} + // OUTPUT: [0000 1001] [0100 0000] = {9, 96} + startOffset = 3; + numBits = 7; + byte data21[] = new byte[7]; + BitBufferHelper.insertBits(data21, inputdata, startOffset, numBits); + Assert.assertTrue(data21[0] == 9); + Assert.assertTrue(data21[1] == 64); + Assert.assertTrue(data21[2] == 0); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96} + // OUTPUT: data = [00000 010] [01011 011] [01110 000] = {37, -73, 0} + startOffset = 5; + numBits = 17; + byte data22[] = new byte[7]; + BitBufferHelper.insertBits(data22, inputdata, startOffset, numBits); + Assert.assertTrue(data22[0] == 2); + Assert.assertTrue(data22[1] == 91); + Assert.assertTrue(data22[2] == 112); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96} + // OUTPUT: [0000 1001] [0110 1101] [110 01101] [01 00000] = {9, 109, -51, 64} + startOffset = 3; + numBits = 23; + byte data23[] = new byte[7]; + BitBufferHelper.insertBits(data23, inputdata, startOffset, numBits); + Assert.assertTrue(data23[0] == 9); + Assert.assertTrue(data23[1] == 109); + Assert.assertTrue(data23[2] == -51); + Assert.assertTrue(data23[3] == 64); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96} + // OUTPUT: [0000 1001] [0110 1101] = {9, 109} + startOffset = 3; + numBits = 13; + byte data24[] = new byte[7]; + BitBufferHelper.insertBits(data24, inputdata, startOffset, numBits); + Assert.assertTrue(data24[0] == 9); + Assert.assertTrue(data24[1] == 109); + Assert.assertTrue(data24[2] == 0); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96} + // OUTPUT: [0000 0100] [1011 0110] [1110 0110] = {4, -74, -26} + startOffset = 4; + numBits = 20; + byte data25[] = new byte[7]; + BitBufferHelper.insertBits(data25, inputdata, startOffset, numBits); + Assert.assertTrue(data25[0] == 4); + Assert.assertTrue(data25[1] == -74); + Assert.assertTrue(data25[2] == -26); + Assert.assertTrue(data25[3] == -0); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96} + // OUTPUT: [0000 0010] [0101 1011] = {0, 2, 91, 0} + startOffset = 13; + numBits = 11; + byte data26[] = new byte[7]; + BitBufferHelper.insertBits(data26, inputdata, startOffset, numBits); + Assert.assertTrue(data26[0] == 0); + Assert.assertTrue(data26[1] == 2); + Assert.assertTrue(data26[2] == 91); + Assert.assertTrue(data26[3] == 0); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96} + // OUTPUT: [000 01001] [011 01101] [110 0 0000] = {9, 109, -64, 0} + startOffset = 3; + numBits = 17; + byte data27[] = new byte[7]; + BitBufferHelper.insertBits(data27, inputdata, startOffset, numBits); + Assert.assertTrue(data27[0] == 9); + Assert.assertTrue(data27[1] == 109); + Assert.assertTrue(data27[2] == -64); + Assert.assertTrue(data27[3] == 0); + + // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} = + // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001] //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96} + // OUTPUT: [00 000000] [00 000000] [00 010010] [11 011011] [10 011010] [11 010100] [0000 0000] = {0, 0, 18, -37,-102,-44,0} + startOffset = 18; + numBits = 34; + byte data28[] = new byte[7]; + BitBufferHelper.insertBits(data28, inputdata, startOffset, numBits); + Assert.assertTrue(data28[0] == 0); + Assert.assertTrue(data28[1] == 0); + Assert.assertTrue(data28[2] == 18); + Assert.assertTrue(data28[3] == -37); + Assert.assertTrue(data28[4] == -102); + Assert.assertTrue(data28[5] == -44); + Assert.assertTrue(data28[6] == 0); + + } + + @Test + public void testGetShort() throws Exception { + byte data[] = new byte[2]; + data[0] = 7; + data[1] = 8; + int length = 9; // num bits + Assert.assertTrue(BitBufferHelper.getShort(data, length) == 264); + + data[0] = 6; + data[1] = 8; + short result = BitBufferHelper.getShort(data, length); + Assert.assertTrue(result == 8); + + data[0] = 8; + data[1] = 47; + result = BitBufferHelper.getShort(data, length); + Assert.assertTrue(result == 47); + + //[0000 0001] [0001 0100] [0110 0100] + byte[] data1 = new byte[2]; + data1[0] = 1; + data1[1] = 20; //data1[2] = 100; + length = 15; + result = BitBufferHelper.getShort(data1, length); + Assert.assertTrue(result == 276); + + byte[] data2 = new byte[2]; + data2[0] = 64; + data2[1] = 99; //data2[2] = 100; + length = 13; + result = BitBufferHelper.getShort(data2, length); + Assert.assertTrue(result == 99); + + byte[] data3 = { 100, 50 }; + result = BitBufferHelper.getShort(data3); + Assert.assertTrue(result == 25650); + } + + @Test + public void testToIntVarLength() throws Exception { + byte data[] = { (byte) 255, (byte) 128 }; + int length = 9; // num bits + Assert.assertTrue(BitBufferHelper.getInt(data, length) == 384); + + byte data2[] = { 0, 8 }; + Assert.assertTrue(BitBufferHelper.getInt(data2, 9) == 8); + + byte data3[] = { 1, 1, 1 }; + Assert.assertTrue(BitBufferHelper.getInt(data3) == 65793); + + byte data4[] = { 1, 1, 1 }; + Assert.assertTrue(BitBufferHelper.getInt(data4) == 65793); + + byte data5[] = { 1, 1 }; + Assert.assertTrue(BitBufferHelper.getInt(data5) == 257); + + } + + @Test + public void testShiftBitstoLSB() { + byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + byte[] data2 = { 8, 9, 10 }; + byte[] shiftedBytes2 = BitBufferHelper.shiftBitsToLSB(data2, 11); + + Assert.assertTrue(shiftedBytes2[0] == 0); + Assert.assertTrue(shiftedBytes2[1] == 64); + Assert.assertTrue(shiftedBytes2[2] == 72); + + byte[] shiftedBytes = BitBufferHelper.shiftBitsToLSB(data, 49); + + Assert.assertTrue(shiftedBytes[0] == 0); + Assert.assertTrue(shiftedBytes[1] == 2); + Assert.assertTrue(shiftedBytes[2] == 4); + Assert.assertTrue(shiftedBytes[3] == 6); + Assert.assertTrue(shiftedBytes[4] == 8); + Assert.assertTrue(shiftedBytes[5] == 10); + Assert.assertTrue(shiftedBytes[6] == 12); + Assert.assertTrue(shiftedBytes[7] == 14); + Assert.assertTrue(shiftedBytes[8] == 16); + Assert.assertTrue(shiftedBytes[9] == 18); + + byte[] data1 = { 1, 2, 3 }; + byte[] shiftedBytes1 = BitBufferHelper.shiftBitsToLSB(data1, 18); + Assert.assertTrue(shiftedBytes1[0] == 0); + Assert.assertTrue(shiftedBytes1[1] == 4); + Assert.assertTrue(shiftedBytes1[2] == 8); + + } + + @Test + public void testShiftBitstoLSBMSB() { + byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + + byte[] clone = BitBufferHelper.shiftBitsToMSB(BitBufferHelper + .shiftBitsToLSB(data, 72), 72); + + Assert.assertTrue(clone[0] == 1); + Assert.assertTrue(clone[1] == 2); + Assert.assertTrue(clone[2] == 3); + Assert.assertTrue(clone[3] == 4); + Assert.assertTrue(clone[4] == 5); + Assert.assertTrue(clone[5] == 6); + Assert.assertTrue(clone[6] == 7); + Assert.assertTrue(clone[7] == 8); + Assert.assertTrue(clone[8] == 9); + Assert.assertTrue(clone[9] == 0); + } + +} diff --git a/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/address/EthernetAddressTest.java b/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/address/EthernetAddressTest.java new file mode 100644 index 0000000000..cfdc7851e3 --- /dev/null +++ b/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/address/EthernetAddressTest.java @@ -0,0 +1,114 @@ + +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +/** + * @file EthernetAddressTest.java + * + * @brief Unit Tests for EthernetAddress class + * + * Unit Tests for EthernetAddress class + */ +package org.opendaylight.controller.sal.packet.address; + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.liblldp.ConstructionException; +import org.opendaylight.controller.liblldp.EthernetAddress; + +public class EthernetAddressTest { + @Test + public void testNonValidConstructor() { + @SuppressWarnings("unused") + EthernetAddress ea1; + // Null input array + try { + ea1 = new EthernetAddress((byte[]) null); + + // Exception is expected if NOT raised test will fail + Assert.assertTrue(false); + } catch (ConstructionException e) { + } + + // Array too short + try { + ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0 }); + + // Exception is expected if NOT raised test will fail + Assert.assertTrue(false); + } catch (ConstructionException e) { + } + + // Array too long + try { + ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0 }); + + // Exception is expected if NOT raised test will fail + Assert.assertTrue(false); + } catch (ConstructionException e) { + } + } + + @Test + public void testEquality() { + EthernetAddress ea1; + EthernetAddress ea2; + try { + ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1 }); + + ea2 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1 }); + Assert.assertTrue(ea1.equals(ea2)); + } catch (ConstructionException e) { + // Exception is NOT expected if raised test will fail + Assert.assertTrue(false); + } + + try { + ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1 }); + + ea2 = ea1.clone(); + Assert.assertTrue(ea1.equals(ea2)); + } catch (ConstructionException e) { + // Exception is NOT expected if raised test will fail + Assert.assertTrue(false); + } + + // Check for well knowns + try { + ea1 = EthernetAddress.BROADCASTMAC; + ea2 = new EthernetAddress(new byte[] { (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }); + Assert.assertTrue(ea1.equals(ea2)); + } catch (ConstructionException e) { + // Exception is NOT expected if raised test will fail + Assert.assertTrue(false); + } + } + + @Test + public void testUnEquality() { + EthernetAddress ea1; + EthernetAddress ea2; + try { + ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2 }); + + ea2 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1 }); + Assert.assertTrue(!ea1.equals(ea2)); + } catch (ConstructionException e) { + // Exception is NOT expected if raised test will fail + Assert.assertTrue(false); + } + } +} diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index 8797c7e85c..3f2c4dacef 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -999,6 +999,11 @@ karaf.branding ${karaf.branding.version} + + org.opendaylight.controller + liblldp + ${sal.version} + org.opendaylight.controller logback-config diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index 7ab56e6d03..969ecc2cbe 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -1106,6 +1106,10 @@ org.opendaylight.controller.md topology-lldp-discovery + + org.opendaylight.controller + liblldp + org.opendaylight.controller.md topology-manager diff --git a/opendaylight/md-sal/topology-lldp-discovery/pom.xml b/opendaylight/md-sal/topology-lldp-discovery/pom.xml index e01a0d5dcb..97ed15df19 100644 --- a/opendaylight/md-sal/topology-lldp-discovery/pom.xml +++ b/opendaylight/md-sal/topology-lldp-discovery/pom.xml @@ -35,11 +35,11 @@ org.opendaylight.controller - sal + sal-binding-api org.opendaylight.controller - sal-binding-api + liblldp org.opendaylight.controller.model diff --git a/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/utils/LLDPDiscoveryUtils.java b/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/utils/LLDPDiscoveryUtils.java index 82ab443246..0d1ba11ee1 100644 --- a/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/utils/LLDPDiscoveryUtils.java +++ b/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/utils/LLDPDiscoveryUtils.java @@ -9,10 +9,10 @@ package org.opendaylight.md.controller.topology.lldp.utils; import java.nio.charset.Charset; -import org.opendaylight.controller.sal.packet.Ethernet; -import org.opendaylight.controller.sal.packet.LLDP; -import org.opendaylight.controller.sal.packet.LLDPTLV; -import org.opendaylight.controller.sal.utils.NetUtils; +import org.opendaylight.controller.liblldp.Ethernet; +import org.opendaylight.controller.liblldp.LLDP; +import org.opendaylight.controller.liblldp.LLDPTLV; +import org.opendaylight.controller.liblldp.NetUtils; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; diff --git a/pom.xml b/pom.xml index 8bebd2aa61..e4c51b7839 100644 --- a/pom.xml +++ b/pom.xml @@ -124,6 +124,7 @@ opendaylight/commons/parent opendaylight/commons/logback_settings opendaylight/commons/filter-valve + opendaylight/commons/liblldp opendaylight/dummy-console -- 2.36.6