Major refactoring of the BMv2 protocol module (onos1.6 cherry-pick)

- Created 3 separate sub-modules: API (doesn't depend on
    Thrift), CTL (depends on Thrift), THRIFT-API (to generate Thrift
    sources)
- Implemented 2 new services (for device configuration swapping and
    table entry management) needed to distribute BMv2-specific state
    among ONOS instances.
- Implemented a BMv2 controller (previously other modules where
    using separately a Thrift client and a server)
- Added a default BMv2 JSON configuration (default.json) and interpreter
    to be used for devices that connect for the first time to ONOS.
    This allows for basic services to work (i.e. LLDP link discovery,
    ARP proxy. etc.).
- Changed behavior of the flow rule translator and extension selector,
    now it allows extension to specify only some of the match parameters
    (before extension selectors were expected to describe the whole
    match key, i.e. all fields)
- Various renaming to better represent the API
- Various java doc fixes / improvements

Change-Id: Ida4b5e546b0def97c3552a6c05f7bce76fd32c28
diff --git a/protocols/bmv2/api/src/main/java/org/onosproject/bmv2/api/utils/Bmv2TranslatorUtils.java b/protocols/bmv2/api/src/main/java/org/onosproject/bmv2/api/utils/Bmv2TranslatorUtils.java
new file mode 100644
index 0000000..8d8966f
--- /dev/null
+++ b/protocols/bmv2/api/src/main/java/org/onosproject/bmv2/api/utils/Bmv2TranslatorUtils.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.bmv2.api.utils;
+
+import org.onlab.util.HexString;
+import org.onlab.util.ImmutableByteSequence;
+
+import java.util.Arrays;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Collection of util methods to deal with flow rule translation.
+ */
+public final class Bmv2TranslatorUtils {
+
+    private Bmv2TranslatorUtils() {
+        // Ban constructor.
+    }
+
+    /**
+     * Returns the number of bytes necessary to contain the given bit-width.
+     *
+     * @param bitWidth an integer value
+     * @return an integer value
+     */
+    public static int roundToBytes(int bitWidth) {
+        return (int) Math.ceil((double) bitWidth / 8);
+    }
+
+    /**
+     * Trims or expands the given byte sequence so to fit a given bit-width.
+     *
+     * @param original a byte sequence
+     * @param bitWidth an integer value
+     * @return a new byte sequence
+     * @throws ByteSequenceFitException if the byte sequence cannot be fitted in the given bit-width
+     */
+    public static ImmutableByteSequence fitByteSequence(ImmutableByteSequence original, int bitWidth)
+            throws ByteSequenceFitException {
+
+        checkNotNull(original, "byte sequence cannot be null");
+        checkArgument(bitWidth > 0, "byte width must a non-zero positive integer");
+
+        int newByteWidth = roundToBytes(bitWidth);
+
+        if (original.size() == newByteWidth) {
+            // nothing to do
+            return original;
+        }
+
+        byte[] originalBytes = original.asArray();
+
+        if (newByteWidth > original.size()) {
+            // pad missing bytes with zeros
+            return ImmutableByteSequence.copyFrom(Arrays.copyOf(originalBytes, newByteWidth));
+        }
+
+        byte[] newBytes = new byte[newByteWidth];
+        // ImmutableByteSequence is always big-endian, hence check the array in reverse order
+        int diff = originalBytes.length - newByteWidth;
+        for (int i = originalBytes.length - 1; i > 0; i--) {
+            byte ob = originalBytes[i]; // original byte
+            byte nb; // new byte
+            if (i > diff) {
+                // no need to truncate, copy as is
+                nb = ob;
+            } else if (i == diff) {
+                // truncate this byte, check if we're loosing something
+                byte mask = (byte) ((1 >> ((bitWidth % 8) + 1)) - 1);
+                if ((ob & ~mask) != 0) {
+                    throw new ByteSequenceFitException(originalBytes, bitWidth);
+                } else {
+                    nb = (byte) (ob & mask);
+                }
+            } else {
+                // drop this byte, check if we're loosing something
+                if (originalBytes[i] != 0) {
+                    throw new ByteSequenceFitException(originalBytes, bitWidth);
+                } else {
+                    continue;
+                }
+            }
+            newBytes[i - diff] = nb;
+        }
+
+        return ImmutableByteSequence.copyFrom(newBytes);
+    }
+
+    /**
+     * A byte sequence fit exception.
+     */
+    public static class ByteSequenceFitException extends Exception {
+        public ByteSequenceFitException(byte[] bytes, int bitWidth) {
+            super("cannot fit " + HexString.toHexString(bytes) + " into a " + bitWidth + " bits value");
+        }
+    }
+}