Skip to content
Snippets Groups Projects
Commit 66183069 authored by Gregor Maier's avatar Gregor Maier
Browse files

Add a utility class to convert EnumSets to/from integer bitmaps for OF types

parent 5a2fe609
No related branches found
No related tags found
No related merge requests found
package net.floodlightcontroller.util;
import java.util.EnumSet;
import java.util.Set;
/**
* A utility class to convert between integer based bitmaps for (OpenFlow)
* flags and Enum and EnumSet based representations.
*
* The enum used to represent individual flags needs to implement the
* BitmapableEnum interface.
*
* Example:
* {@code
* int bitmap = 0x11; // OFPPC_PORT_DOWN | OFPPC_NO_STP
* EnumSet<OFPortConfig> s = toEnumSet(OFPortConfig.class, bitmap);
* // s will contain OFPPC_PORT_DOWN and OFPPC_NO_STP
* }
*
* {@code
* EnumSet<OFPortConfig> s = EnumSet.of(OFPPC_NO_STP, OFPPC_PORT_DOWN);
* int bitmap = toBitmap(s); // returns 0x11
* }
* @author gregor
*
*/
public class EnumBitmaps {
/**
* Enums used to represent individual flags needs to implement this
* interface
*/
public interface BitmapableEnum {
/** Return the value in the bitmap that the enum constant represents.
* The returned value must have only a single bit set. E.g.,1<<3
*/
int getValue();
}
/**
* Convert an integer bitmap to an EnumSet.
*
* See class description for example
* @param type The Enum class to use. Must implement BitmapableEnum
* @param bitmap The integer bitmap
* @return A newly allocated EnumSet representing the bits set in the
* bitmap
* @throws NullPointerException if type is null
* @throws IllegalArgumentException if any enum constant from type has
* more than one bit set.
* @throws IllegalArgumentException if the bitmap has any bits set not
* represented by an enum constant.
*/
public static <E extends Enum<E> & BitmapableEnum>
EnumSet<E> toEnumSet(Class<E> type, int bitmap) {
if (type == null)
throw new NullPointerException("Given enum type must not be null");
EnumSet<E> s = EnumSet.noneOf(type);
// allSetBitmap will eventually have all valid bits for the given
// type set.
int allSetBitmap = 0;
for (E element: type.getEnumConstants()) {
if (Integer.bitCount(element.getValue()) != 1) {
String msg = String.format("The %s (%x) constant of the " +
"enum %s is supposed to represent a bitmap entry but " +
"has more than one bit set.",
element.toString(), element.getValue(), type.getName());
throw new IllegalArgumentException(msg);
}
allSetBitmap |= element.getValue();
if ((bitmap & element.getValue()) != 0)
s.add(element);
}
if (((~allSetBitmap) & bitmap) != 0) {
// check if only valid flags are set in the given bitmap
String msg = String.format("The bitmap %x for enum %s has " +
"bits set that are presented by any enum constant",
bitmap, type.getName());
throw new IllegalArgumentException(msg);
}
return s;
}
/**
* Return the bitmap mask with all possible bits set. E.g., If a bitmap
* has the individual flags 0x1, 0x2, and 0x8 (note the missing 0x4) then
* the mask will be 0xb (1011 binary)
*
* @param type The Enum class to use. Must implement BitmapableEnum
* @throws NullPointerException if type is null
* @throws IllegalArgumentException if any enum constant from type has
* more than one bit set
* @return an integer with all possible bits for the given bitmap enum
* type set.
*/
public static <E extends Enum<E> & BitmapableEnum>
int getMask(Class<E> type) {
if (type == null)
throw new NullPointerException("Given enum type must not be null");
// allSetBitmap will eventually have all valid bits for the given
// type set.
int allSetBitmap = 0;
for (E element: type.getEnumConstants()) {
if (Integer.bitCount(element.getValue()) != 1) {
String msg = String.format("The %s (%x) constant of the " +
"enum %s is supposed to represent a bitmap entry but " +
"has more than one bit set.",
element.toString(), element.getValue(), type.getName());
throw new IllegalArgumentException(msg);
}
allSetBitmap |= element.getValue();
}
return allSetBitmap;
}
/**
* Convert the given EnumSet to the integer bitmap representation
* @param set The EnumSet to convert. The enum must implement
* BitmapableEnum
* @return the integer bitmap
* @throws IllegalArgumentException if an enum constant from the set (!) has
* more than one bit set
* @throws NullPointerException if the set is null
*/
public static <E extends Enum<E> & BitmapableEnum>
int toBitmap(Set<E> set) {
if (set == null)
throw new NullPointerException("Given set must not be null");
int bitmap = 0;
for (E element: set) {
if (Integer.bitCount(element.getValue()) != 1) {
String msg = String.format("The %s (%x) constant in the set " +
"is supposed to represent a bitmap entry but " +
"has more than one bit set.",
element.toString(), element.getValue());
throw new IllegalArgumentException(msg);
}
bitmap |= element.getValue();
}
return bitmap;
}
}
/**
* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
* University
*
*
* 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
......@@ -23,6 +23,7 @@ import java.util.Arrays;
import net.floodlightcontroller.core.web.serializers.ByteArrayMACSerializer;
import net.floodlightcontroller.core.web.serializers.UShortSerializer;
import net.floodlightcontroller.util.EnumBitmaps;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.jboss.netty.buffer.ChannelBuffer;
......@@ -36,43 +37,57 @@ public class OFPhysicalPort {
public final static int MINIMUM_LENGTH = 48;
public final static int OFP_ETH_ALEN = 6;
public enum OFPortConfig {
public enum OFPortConfig implements EnumBitmaps.BitmapableEnum {
OFPPC_PORT_DOWN (1 << 0) {
@Override
public String toString() {
return "port-down (0x1)";
}
},
OFPPC_NO_STP (1 << 1) {
@Override
public String toString() {
return "no-stp (0x2)";
}
},
OFPPC_NO_RECV (1 << 2) {
@Override
public String toString() {
return "no-recv (0x4)";
}
},
OFPPC_NO_RECV_STP (1 << 3) {
@Override
public String toString() {
return "no-recv-stp (0x8)";
}
},
OFPPC_NO_FLOOD (1 << 4) {
@Override
public String toString() {
return "no-flood (0x10)";
}
},
OFPPC_NO_FWD (1 << 5) {
@Override
public String toString() {
return "no-fwd (0x20)";
}
},
OFPPC_NO_PACKET_IN (1 << 6) {
@Override
public String toString() {
return "no-pkt-in (0x40)";
}
},
OFPPC_BSN_MIRROR_DEST (1 << 31) {
@Override
public String toString() {
return "bsn-mirror-dest (0x80000000)";
}
};
protected int value;
private OFPortConfig(int value) {
......@@ -82,6 +97,7 @@ public class OFPhysicalPort {
/**
* @return the value
*/
@Override
public int getValue() {
return value;
}
......@@ -89,31 +105,37 @@ public class OFPhysicalPort {
public enum OFPortState {
OFPPS_LINK_DOWN (1 << 0) {
@Override
public String toString() {
return "link-down (0x1)";
}
},
OFPPS_STP_LISTEN (0 << 8) {
@Override
public String toString() {
return "listen (0x0)";
}
},
OFPPS_STP_LEARN (1 << 8) {
@Override
public String toString() {
return "learn-no-relay (0x100)";
}
},
OFPPS_STP_FORWARD (2 << 8) {
@Override
public String toString() {
return "forward (0x200)";
}
},
OFPPS_STP_BLOCK (3 << 8) {
@Override
public String toString() {
return "block-broadcast (0x300)";
}
},
OFPPS_STP_MASK (3 << 8) {
@Override
public String toString() {
return "block-broadcast (0x300)";
}
......@@ -133,63 +155,75 @@ public class OFPhysicalPort {
}
}
public enum OFPortFeatures {
public enum OFPortFeatures implements EnumBitmaps.BitmapableEnum {
OFPPF_10MB_HD (1 << 0) {
@Override
public String toString() {
return "10mb-hd (0x1)";
}
},
OFPPF_10MB_FD (1 << 1) {
@Override
public String toString() {
return "10mb-fd (0x2)";
}
},
OFPPF_100MB_HD (1 << 2) {
@Override
public String toString() {
return "100mb-hd (0x4)";
}
},
OFPPF_100MB_FD (1 << 3) {
@Override
public String toString() {
return "100mb-fd (0x8)";
}
},
OFPPF_1GB_HD (1 << 4) {
@Override
public String toString() {
return "1gb-hd (0x10)";
}
},
OFPPF_1GB_FD (1 << 5) {
@Override
public String toString() {
return "1gb-fd (0x20)";
}
},
OFPPF_10GB_FD (1 << 6) {
@Override
public String toString() {
return "10gb-fd (0x40)";
}
},
OFPPF_COPPER (1 << 7) {
@Override
public String toString() {
return "copper (0x80)";
}
},
OFPPF_FIBER (1 << 8) {
@Override
public String toString() {
return "fiber (0x100)";
}
},
OFPPF_AUTONEG (1 << 9) {
@Override
public String toString() {
return "autoneg (0x200)";
}
},
OFPPF_PAUSE (1 << 10) {
@Override
public String toString() {
return "pause (0x400)";
}
},
OFPPF_PAUSE_ASYM (1 << 11) {
@Override
public String toString() {
return "pause-asym (0x800)";
}
......@@ -204,6 +238,7 @@ public class OFPhysicalPort {
/**
* @return the value
*/
@Override
public int getValue() {
return value;
}
......
package net.floodlightcontroller.util;
import static org.junit.Assert.*;
import java.util.EnumSet;
import org.junit.Test;
import net.floodlightcontroller.util.EnumBitmaps.BitmapableEnum;
public class EnumBitmapsTest {
private enum ColorEnum implements BitmapableEnum {
RED (1 << 0),
GREEN (1 << 1),
BLUE ( 1 << 3); // note (1<<2) is missing
private int value;
private ColorEnum(int value) {
this.value = value;
}
@Override
public int getValue() {
return value;
}
}
private enum ExtremeEnum implements BitmapableEnum {
SMALL (1 << 0),
BIG ( 1 << 31);
private int value;
private ExtremeEnum(int value) {
this.value = value;
}
@Override
public int getValue() {
return value;
}
}
private enum InvalidEnum implements BitmapableEnum {
FOO_VALID (0x1),
BAR_INVALID (0x6); // Error: more than one bit set
private int value;
private InvalidEnum(int value) {
this.value = value;
}
@Override
public int getValue() {
return value;
}
}
private enum InvalidEnum2 implements BitmapableEnum {
FOOFOO_INVALID (0x0), // error: no bit set
BARBAR_VALID (0x1);
private int value;
private InvalidEnum2(int value) {
this.value = value;
}
@Override
public int getValue() {
return value;
}
}
@Test
public void testNormalBehavior() {
EnumSet<ColorEnum> set = null;
int bitmap = 0;
// With color enum.
bitmap = 0;
set = EnumBitmaps.toEnumSet(ColorEnum.class, bitmap);
assertEquals(EnumSet.noneOf(ColorEnum.class), set);
assertEquals(bitmap, EnumBitmaps.toBitmap(set));
bitmap = ColorEnum.RED.getValue();
set = EnumBitmaps.toEnumSet(ColorEnum.class, bitmap);
assertEquals(EnumSet.of(ColorEnum.RED), set);
assertEquals(bitmap, EnumBitmaps.toBitmap(set));
bitmap = ColorEnum.BLUE.getValue();
set = EnumBitmaps.toEnumSet(ColorEnum.class, bitmap);
assertEquals(EnumSet.of(ColorEnum.BLUE), set);
assertEquals(bitmap, EnumBitmaps.toBitmap(set));
bitmap = ColorEnum.RED.getValue() | ColorEnum.GREEN.getValue();
set = EnumBitmaps.toEnumSet(ColorEnum.class, bitmap);
assertEquals(EnumSet.of(ColorEnum.RED, ColorEnum.GREEN), set);
assertEquals(bitmap, EnumBitmaps.toBitmap(set));
bitmap = ColorEnum.RED.getValue() | ColorEnum.GREEN.getValue() |
ColorEnum.BLUE.getValue();
set = EnumBitmaps.toEnumSet(ColorEnum.class, bitmap);
assertEquals(EnumSet.of(ColorEnum.RED, ColorEnum.GREEN, ColorEnum.BLUE),
set);
assertEquals(bitmap, EnumBitmaps.toBitmap(set));
assertEquals(0xb, EnumBitmaps.getMask(ColorEnum.class));
// with extreme enum. Make sure 1 << 31 is handled correctly
bitmap = 1 << 31;
EnumSet<ExtremeEnum> extremeSet =
EnumBitmaps.toEnumSet(ExtremeEnum.class, bitmap);
assertEquals(EnumSet.of(ExtremeEnum.BIG), extremeSet);
assertEquals(bitmap, EnumBitmaps.toBitmap(extremeSet));
bitmap = (1 << 31) | (1 << 0);
extremeSet = EnumBitmaps.toEnumSet(ExtremeEnum.class, bitmap);
assertEquals(EnumSet.of(ExtremeEnum.BIG, ExtremeEnum.SMALL), extremeSet);
assertEquals(bitmap, EnumBitmaps.toBitmap(extremeSet));
assertEquals(0x80000001, EnumBitmaps.getMask(ExtremeEnum.class));
// there are some cases were InvalidEnum's can actually be used.
// It's fine if a developer chooses to change the behavior and make
// the cases below fail!
EnumSet<InvalidEnum> s1 = EnumSet.of(InvalidEnum.FOO_VALID);
assertEquals(InvalidEnum.FOO_VALID.getValue(),
EnumBitmaps.toBitmap(s1));
EnumSet<InvalidEnum2> s2 = EnumSet.of(InvalidEnum2.BARBAR_VALID);
assertEquals(InvalidEnum2.BARBAR_VALID.getValue(),
EnumBitmaps.toBitmap(s2));
}
@Test
public void testExceptions() {
// Exception when using an invalid enum
try {
EnumBitmaps.toEnumSet(InvalidEnum.class, 0);
fail("Expected exception not thrown");
} catch (IllegalArgumentException e) { }
try {
EnumBitmaps.toEnumSet(InvalidEnum.class, 1);
fail("Expected exception not thrown");
} catch (IllegalArgumentException e) { }
try {
EnumBitmaps.getMask(InvalidEnum.class);
fail("Expected exception not thrown");
} catch (IllegalArgumentException e) { }
try {
EnumSet<InvalidEnum> set = EnumSet.allOf(InvalidEnum.class);
EnumBitmaps.toBitmap(set);
fail("Expected exception not thrown");
} catch (IllegalArgumentException e) { }
try {
EnumSet<InvalidEnum> set = EnumSet.of(InvalidEnum.BAR_INVALID);
EnumBitmaps.toBitmap(set);
fail("Expected exception not thrown");
} catch (IllegalArgumentException e) { }
// Again with a different one
// Exception when using an invalid enum
try {
EnumBitmaps.toEnumSet(InvalidEnum2.class, 0);
fail("Expected exception not thrown");
} catch (IllegalArgumentException e) { }
try {
EnumBitmaps.toEnumSet(InvalidEnum2.class, 1);
fail("Expected exception not thrown");
} catch (IllegalArgumentException e) { }
try {
EnumBitmaps.getMask(InvalidEnum2.class);
fail("Expected exception not thrown");
} catch (IllegalArgumentException e) { }
try {
EnumSet<InvalidEnum2> set = EnumSet.allOf(InvalidEnum2.class);
EnumBitmaps.toBitmap(set);
fail("Expected exception not thrown");
} catch (IllegalArgumentException e) { }
try {
EnumSet<InvalidEnum2> set = EnumSet.of(InvalidEnum2.FOOFOO_INVALID);
EnumBitmaps.toBitmap(set);
fail("Expected exception not thrown");
} catch (IllegalArgumentException e) { }
// NPEs
try {
EnumBitmaps.toEnumSet(null, 0);
fail("Expected exception not thrown");
} catch (NullPointerException e) { }
try {
EnumBitmaps.getMask(null);
fail("Expected exception not thrown");
} catch (NullPointerException e) { }
try {
EnumBitmaps.toBitmap(null);
fail("Expected exception not thrown");
} catch (NullPointerException e) { }
// Bits set that aren't covered by the enum
try {
EnumBitmaps.toEnumSet(ColorEnum.class, 1 << 23);
fail("Expected exception not thrown");
} catch(IllegalArgumentException e) { }
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment