initial import
Change-Id: Ief25aef0066ea96bd2c329ccef974c072b3a5a73
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/HashValueUtilsTest.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/HashValueUtilsTest.java
new file mode 100644
index 0000000..1fe36ac
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/HashValueUtilsTest.java
@@ -0,0 +1,23 @@
+package org.projectfloodlight.openflow.types;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Test;
+
+public class HashValueUtilsTest {
+ @Test
+ public void testBasic() {
+ long key = 0x1234_5678_1234_5678L;
+ long value = 0x8765_4321_8765_4321L;
+ long firstword = 0xFFFF_FFFF_0000_0000L;
+ long secondword = 0x0000_0000_FFFF_FFFFL;
+ long xor = key ^ value;
+
+ assertThat(HashValueUtils.combineWithValue(key, value, 0), equalTo(xor));
+ assertThat(HashValueUtils.combineWithValue(key, value, 64), equalTo(key));
+ assertThat(HashValueUtils.combineWithValue(key, value, 32), equalTo(key & firstword | xor & secondword ));
+ assertThat(HashValueUtils.combineWithValue(key, value, 8), equalTo(0x1251_1559_9551_1559L));
+ }
+
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java
new file mode 100644
index 0000000..865df75
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java
@@ -0,0 +1,67 @@
+package org.projectfloodlight.openflow.types;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.net.UnknownHostException;
+
+import org.junit.Test;
+
+/**
+ * Most tests are in IPv4AddressTest and IPv6AddressTest
+ * Just exception testing here
+ * @author gregor
+ *
+ */
+public class IPAddressTest {
+ @Test
+ public void testOfException() {
+ try {
+ IPAddress.of("Foobar");
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ IPAddressWithMask.of("Foobar");
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ IPAddress.of(null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ try {
+ IPAddressWithMask.of(null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ try {
+ IPAddress.of(null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ try {
+ IPAddressWithMask.of(null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testFromInetAddressException() throws UnknownHostException {
+ try {
+ IPAddress.fromInetAddress(null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ }
+
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java
new file mode 100644
index 0000000..a57b42a
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java
@@ -0,0 +1,371 @@
+package org.projectfloodlight.openflow.types;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.hamcrest.CoreMatchers;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.junit.Test;
+import org.projectfloodlight.openflow.exceptions.OFParseError;
+
+public class IPv4AddressTest {
+ byte[][] testAddresses = new byte[][] {
+ {0x01, 0x02, 0x03, 0x04 },
+ {127, 0, 0, 1},
+ {(byte) 192, (byte) 168, 0, 100 },
+ {(byte) 255, (byte) 255, (byte) 255, (byte) 255 }
+ };
+
+ String[] testStrings = {
+ "1.2.3.4",
+ "127.0.0.1",
+ "192.168.0.100",
+ "255.255.255.255"
+ };
+
+ int[] testInts = {
+ 0x01020304,
+ 0x7f000001,
+ (192 << 24) | (168 << 16) | 100,
+ 0xffffffff
+ };
+
+ String[] invalidIPs = {
+ "",
+ ".",
+ "1.2..3.4",
+ "1.2.3.4.",
+ "257.11.225.1",
+ "256.11.225.1",
+ "-1.2.3.4",
+ "1.2.3.4.5",
+ "1.x.3.4",
+ "1.2x.3.4"
+ };
+
+ String[] ipsWithMask = {
+ "1.2.3.4/24",
+ "192.168.130.140/255.255.192.0",
+ "127.0.0.1/8",
+ "8.8.8.8",
+ "8.8.8.8/32",
+ "0.0.0.0/0",
+ "192.168.130.140/255.0.255.0",
+ "1.2.3.4/0.127.0.255"
+ };
+
+ boolean[] hasMask = {
+ true,
+ true,
+ true,
+ false,
+ false,
+ true,
+ true,
+ true
+ };
+
+ byte[][][] ipsWithMaskValues = {
+ new byte[][] { new byte[] { (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04 }, new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00 } },
+ new byte[][] { new byte[] { (byte)0xC0, (byte)0xA8, (byte)0x82, (byte)0x8C }, new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xC0, (byte)0x00 } },
+ new byte[][] { new byte[] { (byte)0x7F, (byte)0x00, (byte)0x00, (byte)0x01 }, new byte[] { (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00 } },
+ new byte[][] { new byte[] { (byte)0x08, (byte)0x08, (byte)0x08, (byte)0x08 }, new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF } },
+ new byte[][] { new byte[] { (byte)0x08, (byte)0x08, (byte)0x08, (byte)0x08 }, new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF } },
+ new byte[][] { new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }, new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 } },
+ new byte[][] { new byte[] { (byte)0xC0, (byte)0xA8, (byte)0x82, (byte)0x8C }, new byte[] { (byte)0xFF, (byte)0x00, (byte)0xFF, (byte)0x00 } },
+ new byte[][] { new byte[] { (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04 }, new byte[] { (byte)0x00, (byte)0x7F, (byte)0x00, (byte)0xFF } }
+ };
+
+ int[] ipsWithMaskLengths = {
+ 24,
+ 18,
+ 8,
+ 32,
+ 32,
+ 0,
+ -1,
+ -1
+ };
+
+ String[] invalidIpsWithMask = {
+ "asdf",
+ "1.2.3.4/33",
+ "1.2.3.4/34",
+ "1.2.3.4/-1",
+ "1.2.3.4/256.0.0.0",
+ "1.256.3.4/255.255.0.0",
+ "1.2.3.4/255.255.0.0.0",
+ };
+
+ @Test
+ public void testLogicalOperatorsBroadcast() {
+ assertTrue(IPv4Address.NO_MASK.not().equals(IPv4Address.FULL_MASK));
+ assertTrue(IPv4Address.NO_MASK.or(IPv4Address.FULL_MASK).
+ equals(IPv4Address.NO_MASK));
+ assertTrue(IPv4Address.NO_MASK.and(IPv4Address.FULL_MASK).
+ equals(IPv4Address.FULL_MASK));
+
+ assertTrue(IPv4Address.NO_MASK.isBroadcast());
+ assertTrue(!IPv4Address.FULL_MASK.isBroadcast());
+ }
+
+ @Test
+ public void testMaskedSubnetBroadcast() {
+ assertTrue(IPv4AddressWithMask.of("10.10.10.1/24")
+ .getSubnetBroadcastAddress()
+ .equals(IPv4Address.of("10.10.10.255")));
+ assertTrue(IPv4AddressWithMask.of("10.10.10.1/24")
+ .isSubnetBroadcastAddress(IPv4Address.of("10.10.10.255")));
+ assertTrue(!IPv4AddressWithMask.of("10.10.10.1/24")
+ .isSubnetBroadcastAddress(IPv4Address.of("10.10.10.254")));
+ }
+
+ @Test
+ public void testMaskedMatchesCidr() {
+ IPv4AddressWithMask slash28 = IPv4AddressWithMask.of("10.0.42.16/28");
+
+ String[] notContained = {"0.0.0.0", "11.0.42.16", "10.0.41.1", "10.0.42.0", "10.0.42.15",
+ "10.0.42.32", "255.255.255.255" };
+
+ for(String n: notContained) {
+ assertThat(String.format("slash 28 %s should not contain address %s",
+ slash28, n),
+ slash28.matches(IPv4Address.of(n)), equalTo(false));
+ }
+ for(int i=16; i < 32; i++) {
+ IPv4Address c = IPv4Address.of(String.format("10.0.42.%d", i));
+ assertThat(String.format("slash 28 %s should contain address %s",
+ slash28, c),
+ slash28.matches(c), equalTo(true));
+ }
+ }
+
+ @Test
+ public void testMaskedMatchesArbitrary() {
+ // irregular octect on the 3rd bitmask requires '1'bit to be set
+ // 4 bit unset, all others arbitrary
+ IPv4AddressWithMask slash28 = IPv4AddressWithMask.of("1.2.1.4/255.255.5.255");
+
+ String[] notContained = {"0.0.0.0", "1.2.3.5", "1.2.3.3",
+ "1.2.0.4", "1.2.2.4", "1.2.4.4", "1.2.5.4", "1.2.6.4", "1.2.7.4",
+ "1.2.8.4", "1.2.12.4", "1.2.13.4"
+ };
+ String[] contained = {"1.2.1.4", "1.2.3.4", "1.2.9.4", "1.2.11.4", "1.2.251.4",
+ };
+
+ for(String n: notContained) {
+ assertThat(String.format("slash 28 %s should not contain address %s",
+ slash28, n),
+ slash28.matches(IPv4Address.of(n)), equalTo(false));
+ }
+ for(String c: contained) {
+ IPv4Address addr = IPv4Address.of(c);
+ assertThat(String.format("slash 28 %s should contain address %s",
+ slash28, addr),
+ slash28.matches(addr), equalTo(true));
+ }
+
+ }
+
+
+ @Test
+ public void testConstants() {
+ byte[] zeros = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };
+ byte[] ones = { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF };
+ // Make sure class initializtation and static assignment don't get
+ // messed up. Test everything twice for cached values
+ assertTrue(IPv4Address.NONE.isCidrMask());
+ assertEquals(0, IPv4Address.NONE.asCidrMaskLength());
+ assertArrayEquals(zeros, IPv4Address.NONE.getBytes());
+ assertTrue(IPv4Address.NONE.isCidrMask());
+ assertEquals(0, IPv4Address.NONE.asCidrMaskLength());
+ assertArrayEquals(zeros, IPv4Address.NONE.getBytes());
+
+ assertTrue(IPv4Address.NO_MASK.isCidrMask());
+ assertEquals(32, IPv4Address.NO_MASK.asCidrMaskLength());
+ assertArrayEquals(ones, IPv4Address.NO_MASK.getBytes());
+ assertTrue(IPv4Address.NO_MASK.isCidrMask());
+ assertEquals(32, IPv4Address.NO_MASK.asCidrMaskLength());
+ assertArrayEquals(ones, IPv4Address.NO_MASK.getBytes());
+
+ assertTrue(IPv4Address.FULL_MASK.isCidrMask());
+ assertEquals(0, IPv4Address.FULL_MASK.asCidrMaskLength());
+ assertArrayEquals(zeros, IPv4Address.FULL_MASK.getBytes());
+ assertTrue(IPv4Address.FULL_MASK.isCidrMask());
+ assertEquals(0, IPv4Address.FULL_MASK.asCidrMaskLength());
+ assertArrayEquals(zeros, IPv4Address.FULL_MASK.getBytes());
+ }
+
+
+ @Test
+ public void testOfString() {
+ for(int i=0; i < testAddresses.length; i++ ) {
+ IPv4Address ip = IPv4Address.of(testStrings[i]);
+ assertEquals(testInts[i], ip.getInt());
+ assertArrayEquals(testAddresses[i], ip.getBytes());
+ assertEquals(testStrings[i], ip.toString());
+ }
+ }
+
+ @Test
+ public void testOfByteArray() {
+ for(int i=0; i < testAddresses.length; i++ ) {
+ IPv4Address ip = IPv4Address.of(testAddresses[i]);
+ assertEquals(testInts[i], ip.getInt());
+ assertArrayEquals(testAddresses[i], ip.getBytes());
+ assertEquals(testStrings[i], ip.toString());
+ }
+ }
+
+ @Test
+ public void testReadFrom() throws OFParseError {
+ for(int i=0; i < testAddresses.length; i++ ) {
+ IPv4Address ip = IPv4Address.read4Bytes(ChannelBuffers.copiedBuffer(testAddresses[i]));
+ assertEquals(testInts[i], ip.getInt());
+ assertArrayEquals(testAddresses[i], ip.getBytes());
+ assertEquals(testStrings[i], ip.toString());
+ }
+ }
+
+
+ @Test
+ public void testInvalidIPs() throws OFParseError {
+ for(String invalid : invalidIPs) {
+ try {
+ IPv4Address.of(invalid);
+ fail("Invalid IP "+invalid+ " should have raised IllegalArgumentException");
+ } catch(IllegalArgumentException e) {
+ // ok
+ }
+ }
+ }
+
+ @Test
+ public void testOfMasked() throws OFParseError {
+ for (int i = 0; i < ipsWithMask.length; i++) {
+ IPv4AddressWithMask value = IPv4AddressWithMask.of(ipsWithMask[i]);
+ if (!hasMask[i]) {
+ IPv4Address ip = value.getValue();
+ assertArrayEquals(ipsWithMaskValues[i][0], ip.getBytes());
+ }
+ IPv4Address mask = value.getMask();
+ if (ipsWithMaskLengths[i] == -1) {
+ assertFalse(mask.isCidrMask());
+ try {
+ mask.asCidrMaskLength();
+ fail("Expected IllegalStateException not thrown");
+ } catch(IllegalStateException e) {
+ //expected
+ }
+ } else {
+ assertTrue(mask.isCidrMask());
+ assertEquals(ipsWithMaskLengths[i], mask.asCidrMaskLength());
+ }
+ assertArrayEquals(ipsWithMaskValues[i][1], mask.getBytes());
+ byte[] ipBytes = new byte[4];
+ System.arraycopy(ipsWithMaskValues[i][0], 0, ipBytes, 0, 4);
+ assertEquals(ipBytes.length, value.getValue().getBytes().length);
+ for (int j = 0; j < ipBytes.length; j++) {
+ ipBytes[j] &= ipsWithMaskValues[i][1][j];
+ }
+
+ assertArrayEquals(ipBytes, value.getValue().getBytes());
+ assertThat(String.format("Byte comparison for mask of %s (%s)", ipsWithMask[i], value),
+ value.getMask().getBytes(), CoreMatchers.equalTo(ipsWithMaskValues[i][1]));
+ }
+ }
+
+ @Test
+ public void testOfMaskedInvalid() throws Exception {
+ for(String invalid : invalidIpsWithMask) {
+ try {
+ IPv4Address.of(invalid);
+ fail("Invalid IP "+invalid+ " should have raised IllegalArgumentException");
+ } catch(IllegalArgumentException e) {
+ // ok
+ }
+ }
+ }
+
+ @Test
+ public void testSuperclass() throws Exception {
+ for(String ipString: testStrings) {
+ IPAddress<?> superIp = IPAddress.of(ipString);
+ assertEquals(IPVersion.IPv4, superIp.getIpVersion());
+ assertEquals(IPv4Address.of(ipString), superIp);
+ }
+
+ for(String ipMaskedString: ipsWithMask) {
+ IPAddressWithMask<?> superIp = IPAddressWithMask.of(ipMaskedString);
+ assertEquals(IPVersion.IPv4, superIp.getIpVersion());
+ assertEquals(IPv4AddressWithMask.of(ipMaskedString), superIp);
+ }
+ }
+
+ @Test
+ public void testOfExceptions() {
+ // We check if the message of a caught NPE is set to a useful message
+ // as a hacky way of verifying that we got an NPE thrown by use rather
+ // than one the JVM created for a null access.
+ try {
+ String s = null;
+ IPv4Address.of(s);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ try {
+ byte[] b = null;
+ IPv4Address.of(b);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ try {
+ byte[] b = new byte[3];
+ IPv4Address.of(b);
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ byte[] b = new byte[5];
+ IPv4Address.of(b);
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ IPv4AddressWithMask.of(null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ try {
+ IPv4AddressWithMask.of(IPv4Address.of("1.2.3.4"), null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ try {
+ IPv4AddressWithMask.of(null, IPv4Address.of("255.0.0.0"));
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ try {
+ IPv4AddressWithMask.of(IPv4Address.of("10.10.10.0"),
+ IPv4Address.of("255.0.255.0"))
+ .getSubnetBroadcastAddress();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ assertNotNull(e.getMessage());
+ }
+ }
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
new file mode 100644
index 0000000..6963c21
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
@@ -0,0 +1,317 @@
+package org.projectfloodlight.openflow.types;
+
+import static org.junit.Assert.*;
+
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.hamcrest.CoreMatchers;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.junit.Test;
+import org.projectfloodlight.openflow.exceptions.OFParseError;
+
+import com.google.common.io.BaseEncoding;
+
+public class IPv6AddressTest {
+
+ String[] testStrings = {
+ "::",
+ "::1",
+ "ffe0::",
+ "1:2:3:4:5:6:7:8"
+ };
+
+
+ private final BaseEncoding hex = BaseEncoding.base16().omitPadding().lowerCase();
+
+ private class WithMaskTaskCase {
+ final String input;
+ boolean hasMask;
+ int expectedMaskLength = 128;
+ byte[] expectedMask = hex.decode("ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff".replaceAll(" ", ""));
+
+ public WithMaskTaskCase(String input) {
+ super();
+ this.input = input;
+ }
+
+ public WithMaskTaskCase maskHex(String string) {
+ string = string.replaceAll(" ", "");
+ this.hasMask = true;
+ expectedMask = hex.decode(string);
+ return this;
+ }
+
+ public WithMaskTaskCase expectedMaskLength(int expectedLength) {
+ this.expectedMaskLength = expectedLength;
+ return this;
+ }
+
+ }
+
+ WithMaskTaskCase[] withMasks = new WithMaskTaskCase[] {
+ new WithMaskTaskCase("1::1/80")
+ .maskHex("ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00")
+ .expectedMaskLength(80),
+
+ new WithMaskTaskCase("ffff:ffee:1::/ff00:ff00:ff00:ff00::")
+ .maskHex("ff 00 ff 00 ff 00 ff 00 00 00 00 00 00 00 00 00")
+ .expectedMaskLength(-1),
+ new WithMaskTaskCase("1:2:3:4:5:6:7:8/1::ff00:ff00")
+ .maskHex("00 01 00 00 00 00 00 00 00 00 00 00 ff 00 ff 00")
+ .expectedMaskLength(-1),
+ new WithMaskTaskCase("1:2:3:4:5:6:7:8/::ff00:ff00")
+ .maskHex("00 00 00 00 00 00 00 00 00 00 00 00 ff 00 ff 00")
+ .expectedMaskLength(-1),
+ new WithMaskTaskCase("1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff::ff00:ff00")
+ .maskHex("ff ff ff ff ff ff ff ff ff ff 00 00 ff 00 ff 00")
+ .expectedMaskLength(-1),
+ new WithMaskTaskCase("8:8:8:8:8:8:8:8"),
+ new WithMaskTaskCase("8:8:8:8:8:8:8:8"),
+ new WithMaskTaskCase("1:2:3:4:5:6:7:8/128"),
+ new WithMaskTaskCase("::/0")
+ .maskHex("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00")
+ .expectedMaskLength(0),
+ };
+
+ @Test
+ public void testLogicalOperatorsBroadcast() {
+ assertTrue(IPv6Address.NO_MASK.not().equals(IPv6Address.FULL_MASK));
+ assertTrue(IPv6Address.NO_MASK.or(IPv6Address.FULL_MASK).
+ equals(IPv6Address.NO_MASK));
+ assertTrue(IPv6Address.NO_MASK.and(IPv6Address.FULL_MASK).
+ equals(IPv6Address.FULL_MASK));
+
+ assertTrue(IPv6Address.NO_MASK.isBroadcast());
+ assertTrue(!IPv6Address.FULL_MASK.isBroadcast());
+ }
+
+ @Test
+ public void testMaskedSubnetBroadcast() {
+ assertTrue(IPv6AddressWithMask.of("10:10::1/112")
+ .getSubnetBroadcastAddress()
+ .equals(IPv6Address.of("10:10::ffff")));
+ assertTrue(IPv6AddressWithMask.of("10:10::1/112")
+ .isSubnetBroadcastAddress(IPv6Address.of("10:10::ffff")));
+ assertTrue(!IPv6AddressWithMask.of("10:10::1/112")
+ .isSubnetBroadcastAddress(IPv6Address.of("10:10::fffd")));
+ }
+
+ @Test
+ public void testConstants() {
+ byte[] zeros = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };
+ byte[] ones = { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
+ (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
+ (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
+ (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF };
+ // Make sure class initializtation and static assignment don't get
+ // messed up. Test everything twice for cached values
+ assertTrue(IPv6Address.NONE.isCidrMask());
+ assertEquals(0, IPv6Address.NONE.asCidrMaskLength());
+ assertArrayEquals(zeros, IPv6Address.NONE.getBytes());
+ assertTrue(IPv6Address.NONE.isCidrMask());
+ assertEquals(0, IPv6Address.NONE.asCidrMaskLength());
+ assertArrayEquals(zeros, IPv6Address.NONE.getBytes());
+
+ assertTrue(IPv6Address.NO_MASK.isCidrMask());
+ assertEquals(128, IPv6Address.NO_MASK.asCidrMaskLength());
+ assertArrayEquals(ones, IPv6Address.NO_MASK.getBytes());
+ assertTrue(IPv6Address.NO_MASK.isCidrMask());
+ assertEquals(128, IPv6Address.NO_MASK.asCidrMaskLength());
+ assertArrayEquals(ones, IPv6Address.NO_MASK.getBytes());
+
+ assertTrue(IPv6Address.FULL_MASK.isCidrMask());
+ assertEquals(0, IPv6Address.FULL_MASK.asCidrMaskLength());
+ assertArrayEquals(zeros, IPv6Address.FULL_MASK.getBytes());
+ assertTrue(IPv6Address.FULL_MASK.isCidrMask());
+ assertEquals(0, IPv6Address.FULL_MASK.asCidrMaskLength());
+ assertArrayEquals(zeros, IPv6Address.FULL_MASK.getBytes());
+ }
+
+ @Test
+ public void testMasked() throws UnknownHostException {
+ for(WithMaskTaskCase w: withMasks) {
+ IPv6AddressWithMask value = IPv6AddressWithMask.of(w.input);
+ if (!w.hasMask) {
+ IPv6Address ip = value.getValue();
+ InetAddress inetAddress = InetAddress.getByName(w.input.split("/")[0]);
+
+ assertArrayEquals(ip.getBytes(), inetAddress.getAddress());
+ assertEquals(w.input.split("/")[0], ip.toString());
+ }
+ InetAddress inetAddress = InetAddress.getByName(w.input.split("/")[0]);
+
+ if (w.expectedMaskLength == -1) {
+ assertFalse(value.getMask().isCidrMask());
+ try {
+ value.getMask().asCidrMaskLength();
+ fail("Expected IllegalStateException not thrown");
+ } catch(IllegalStateException e) {
+ //expected
+ }
+ } else {
+ assertTrue(value.getMask().isCidrMask());
+ assertEquals("Input " + w.input, w.expectedMaskLength,
+ value.getMask().asCidrMaskLength());
+ }
+
+ byte[] address = inetAddress.getAddress();
+ assertEquals(address.length, value.getValue().getBytes().length);
+
+ for (int j = 0; j < address.length; j++) {
+ address[j] &= w.expectedMask[j];
+ }
+
+ assertThat("Address bytes for input " + w.input + ", value=" + value, value.getValue().getBytes(), CoreMatchers.equalTo(address));
+ assertThat("mask check for input " + w.input + ", value=" + value, value.getMask().getBytes(), CoreMatchers.equalTo(w.expectedMask));
+ }
+ for (int i = 0; i <= 128; i++) {
+ String ipString = String.format("8001:2::1/%d", i);
+ IPv6AddressWithMask value = IPv6AddressWithMask.of(ipString);
+ assertEquals("Input " + ipString, i, value.getMask().asCidrMaskLength());
+ }
+ }
+
+
+ @Test
+ public void testOfString() throws UnknownHostException {
+ for(int i=0; i < testStrings.length; i++ ) {
+ IPv6Address ip = IPv6Address.of(testStrings[i]);
+ InetAddress inetAddress = InetAddress.getByName(testStrings[i]);
+
+ assertArrayEquals(ip.getBytes(), inetAddress.getAddress());
+ assertEquals(testStrings[i], ip.toString());
+ }
+ }
+
+ @Test
+ public void testOfByteArray() throws UnknownHostException {
+ for(int i=0; i < testStrings.length; i++ ) {
+ byte[] bytes = Inet6Address.getByName(testStrings[i]).getAddress();
+ IPv6Address ip = IPv6Address.of(bytes);
+ assertEquals(testStrings[i], ip.toString());
+ assertArrayEquals(bytes, ip.getBytes());
+ }
+ }
+
+ @Test
+ public void testReadFrom() throws OFParseError, UnknownHostException {
+ for(int i=0; i < testStrings.length; i++ ) {
+ byte[] bytes = Inet6Address.getByName(testStrings[i]).getAddress();
+ IPv6Address ip = IPv6Address.read16Bytes(ChannelBuffers.copiedBuffer(bytes));
+ assertEquals(testStrings[i], ip.toString());
+ assertArrayEquals(bytes, ip.getBytes());
+ }
+ }
+
+ String[] invalidIPs = {
+ "",
+ ":",
+ "1:2:3:4:5:6:7:8:9",
+ "1:2:3:4:5:6:7:8:",
+ "1:2:3:4:5:6:7:8g",
+ "1:2:3:",
+ "12345::",
+ "1::3::8",
+ "::3::"
+ };
+
+ @Test
+ public void testInvalidIPs() throws OFParseError {
+ for(String invalid : invalidIPs) {
+ try {
+ IPv6Address.of(invalid);
+ fail("Invalid IP "+invalid+ " should have raised IllegalArgumentException");
+ } catch(IllegalArgumentException e) {
+ // ok
+ }
+ }
+ }
+
+ @Test
+ public void testZeroCompression() throws OFParseError {
+ assertEquals("::", IPv6Address.of("::").toString(true, false));
+ assertEquals("0:0:0:0:0:0:0:0", IPv6Address.of("::").toString(false, false));
+ assertEquals("0000:0000:0000:0000:0000:0000:0000:0000", IPv6Address.of("::").toString(false, true));
+ assertEquals("1::4:5:6:0:8", IPv6Address.of("1:0:0:4:5:6:0:8").toString(true, false));
+ assertEquals("1:0:0:4::8", IPv6Address.of("1:0:0:4:0:0:0:8").toString(true, false));
+ }
+
+ @Test
+ public void testSuperclass() throws Exception {
+ for(String ipString: testStrings) {
+ IPAddress<?> superIp = IPAddress.of(ipString);
+ assertEquals(IPVersion.IPv6, superIp.getIpVersion());
+ assertEquals(IPv6Address.of(ipString), superIp);
+ }
+
+ for(WithMaskTaskCase w: withMasks) {
+ String ipMaskedString = w.input;
+ IPAddressWithMask<?> superIp = IPAddressWithMask.of(ipMaskedString);
+ assertEquals(IPVersion.IPv6, superIp.getIpVersion());
+ assertEquals(IPv6AddressWithMask.of(ipMaskedString), superIp);
+ }
+ }
+
+ @Test
+ public void testOfExceptions() throws Exception {
+ try {
+ IPv6AddressWithMask.of(null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ try {
+ String s = null;
+ IPv6Address.of(s);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ try {
+ byte[] b = null;
+ IPv6Address.of(b);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ try {
+ byte[] b = new byte[7];
+ IPv6Address.of(b);
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ byte[] b = new byte[9];
+ IPv6Address.of(b);
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ IPv6AddressWithMask.of(IPv6Address.of("1::"), null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ try {
+ IPv6AddressWithMask.of(null, IPv6Address.of("255::"));
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ assertNotNull(e.getMessage());
+ }
+ try {
+ IPv6AddressWithMask.of(IPv6Address.of("10:10::0"),
+ IPv6Address.of("ffff:0:ffff::"))
+ .getSubnetBroadcastAddress();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ assertNotNull(e.getMessage());
+ }
+ }
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/MacAddressTest.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/MacAddressTest.java
new file mode 100644
index 0000000..a13fdd4
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/MacAddressTest.java
@@ -0,0 +1,154 @@
+package org.projectfloodlight.openflow.types;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.junit.Test;
+import org.projectfloodlight.openflow.exceptions.OFParseError;
+
+public class MacAddressTest {
+ byte[][] testAddresses = new byte[][] {
+ {0x01, 0x02, 0x03, 0x04, 0x05, 0x06 },
+ {(byte) 0x80, 0x0, 0x0, 0x0, 0x0, 0x01},
+ {(byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255 }
+ };
+
+ String[] testStrings = {
+ "01:02:03:04:05:06",
+ "80:00:00:00:00:01",
+ "ff:ff:ff:ff:ff:ff"
+ };
+
+ long[] testInts = {
+ 0x00010203040506L,
+ 0x00800000000001L,
+ 0x00ffffffffffffL
+ };
+
+ String[] invalidMacStrings = {
+ "",
+ "1.2.3.4",
+ "0T:00:01:02:03:04",
+ "00:01:02:03:04:05:06",
+ "00:ff:ef:12:12:ff:",
+ "00:fff:ef:12:12:ff",
+ "01:02:03:04:05;06",
+ "0:1:2:3:4:5:6",
+ "01:02:03:04"
+ };
+
+ byte[][] invalidMacBytes = {
+ new byte[]{0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
+ new byte[]{0x01, 0x01, 0x02, 0x03, 0x04}
+ };
+
+ @Test
+ public void testOfString() {
+ for(int i=0; i < testAddresses.length; i++ ) {
+ MacAddress ip = MacAddress.of(testStrings[i]);
+ assertEquals(testInts[i], ip.getLong());
+ assertArrayEquals(testAddresses[i], ip.getBytes());
+ assertEquals(testStrings[i], ip.toString());
+ }
+ }
+
+ @Test
+ public void testOfByteArray() {
+ for(int i=0; i < testAddresses.length; i++ ) {
+ MacAddress ip = MacAddress.of(testAddresses[i]);
+ assertEquals("error checking long representation of "+Arrays.toString(testAddresses[i]) + "(should be "+Long.toHexString(testInts[i]) +")", testInts[i], ip.getLong());
+ assertArrayEquals(testAddresses[i], ip.getBytes());
+ assertEquals(testStrings[i], ip.toString());
+ }
+ }
+
+ @Test
+ public void testReadFrom() throws OFParseError {
+ for(int i=0; i < testAddresses.length; i++ ) {
+ MacAddress ip = MacAddress.read6Bytes(ChannelBuffers.copiedBuffer(testAddresses[i]));
+ assertEquals(testInts[i], ip.getLong());
+ assertArrayEquals(testAddresses[i], ip.getBytes());
+ assertEquals(testStrings[i], ip.toString());
+ }
+ }
+
+
+ @Test
+ public void testInvalidMacStrings() throws OFParseError {
+ for(String invalid : invalidMacStrings) {
+ try {
+ MacAddress.of(invalid);
+ fail("Invalid MAC address "+invalid+ " should have raised IllegalArgumentException");
+ } catch(IllegalArgumentException e) {
+ // ok
+ }
+ }
+ }
+
+ @Test
+ public void testInvalidMacBytes() throws OFParseError {
+ for(byte[] invalid : invalidMacBytes) {
+ try {
+ MacAddress.of(invalid);
+ fail("Invalid MAC address bytes "+ Arrays.toString(invalid) + " should have raised IllegalArgumentException");
+ } catch(IllegalArgumentException e) {
+ // ok
+ }
+ }
+ }
+
+ // Test data is imported from org.projectfloodlight.packet.EthernetTest
+ @Test
+ public void testToLong() {
+ assertEquals(
+ 281474976710655L,
+ MacAddress.of(new byte[]{(byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}).getLong());
+
+ assertEquals(
+ 1103823438081L,
+ MacAddress.of(new byte[] { (byte) 0x01, (byte) 0x01,
+ (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01 }).getLong());
+
+ assertEquals(
+ 141289400074368L,
+ MacAddress.of(new byte[] { (byte) 0x80, (byte) 0x80,
+ (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80 }).getLong());
+
+ }
+
+ @Test
+ public void testIsBroadcast() {
+ assertTrue(MacAddress.of("FF:FF:FF:FF:FF:FF").isBroadcast());
+ assertTrue(MacAddress.of(-1).isBroadcast());
+ assertTrue(MacAddress.of(0x05FFFFFFFFFFFFL).isBroadcast());
+ assertFalse(MacAddress.of("11:22:33:44:55:66").isBroadcast());
+ }
+
+ @Test
+ public void testIsMulticast() {
+ assertTrue(MacAddress.of("01:80:C2:00:00:00").isMulticast());
+ assertFalse(MacAddress.of("00:80:C2:00:00:00").isMulticast());
+ assertFalse(MacAddress.of("FE:80:C2:00:00:00").isMulticast());
+ assertFalse(MacAddress.of(-1).isMulticast());
+ assertFalse(MacAddress.of(0x05FFFFFFFFFFFFL).isMulticast());
+ assertFalse(MacAddress.of("FF:FF:FF:FF:FF:FF").isMulticast());
+ }
+
+ @Test
+ public void testIsLLDPAddress() {
+ assertTrue(MacAddress.of("01:80:C2:00:00:00").isLLDPAddress());
+ assertTrue(MacAddress.of("01:80:C2:00:00:0f").isLLDPAddress());
+ assertFalse(MacAddress.of("01:80:C2:00:00:50").isLLDPAddress());
+ assertFalse(MacAddress.of("01:80:C2:00:10:00").isLLDPAddress());
+ assertFalse(MacAddress.of("01:80:C2:40:00:01").isLLDPAddress());
+ assertFalse(MacAddress.of("00:80:C2:f0:00:00").isLLDPAddress());
+ assertFalse(MacAddress.of("FE:80:C2:00:00:00").isLLDPAddress());
+ }
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/OFErrorCauseDataTest.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/OFErrorCauseDataTest.java
new file mode 100644
index 0000000..9a5a4dc
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/OFErrorCauseDataTest.java
@@ -0,0 +1,74 @@
+package org.projectfloodlight.openflow.types;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import org.hamcrest.Matchers;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.junit.Test;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+
+public class OFErrorCauseDataTest {
+ @Test
+ public void testEmpty() {
+ OFErrorCauseData emptyCause = OFErrorCauseData.of(new byte[] {}, OFVersion.OF_13);
+ assertThat(emptyCause.getData(), equalTo(new byte[] {}));
+ assertThat(emptyCause.getParsedMessage().isPresent(), equalTo(false));
+ assertThat(emptyCause.toString(), Matchers.containsString("unparsed"));
+ }
+
+ @Test
+ public void testTooShort() {
+ OFErrorCauseData emptyCause = OFErrorCauseData.of(new byte[] {0x1, 0x2}, OFVersion.OF_13);
+ assertThat(emptyCause.getData(), equalTo(new byte[] {0x1, 0x2}));
+ assertThat(emptyCause.getParsedMessage().isPresent(), equalTo(false));
+ assertThat(emptyCause.toString(), Matchers.containsString("unparsed"));
+ assertThat(emptyCause.toString(), Matchers.containsString("01 02"));
+ }
+
+ byte[] truncatedFlowAddd = new byte[] {
+ 0x04, 0x0e, // version, type
+ 0x00, (byte) 0x80, // length
+ 0x12, 0x34, 0x56, 0x78, // xid
+ (byte) 0xfe, (byte) 0xdc , (byte) 0xba, (byte) 0x98, 0x76, 0x54, 0x32, 0x10, // cookie
+ (byte) 0xff, 0x00, (byte) 0xff, 0x00, (byte) 0xff, 0x00, (byte) 0xff, 0x00, // cookie_mask
+ 0x03 // table_id
+ // rest truncated
+ };
+
+ @Test
+ public void testTruncated() {
+ OFErrorCauseData emptyCause = OFErrorCauseData.of(truncatedFlowAddd, OFVersion.OF_13);
+ assertThat(emptyCause.getData(), equalTo(truncatedFlowAddd));
+ assertThat(emptyCause.getParsedMessage().isPresent(), equalTo(false));
+ assertThat(emptyCause.toString(), Matchers.containsString("unparsed"));
+ assertThat(emptyCause.toString(), Matchers.containsString("04 0e 00 80"));
+ }
+
+ @Test
+ public void testFlowAdd() {
+ OFFlowAdd flowAdd = OFFactories.getFactory(OFVersion.OF_13).buildFlowAdd()
+ .setXid(0x12345678)
+ .setCookie(U64.parseHex("FEDCBA9876543210"))
+ .setCookieMask(U64.parseHex("FF00FF00FF00FF00"))
+ .setTableId(TableId.of(3))
+ .setIdleTimeout(5)
+ .setHardTimeout(10)
+ .setPriority(6000)
+ .build();
+
+ ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
+ flowAdd.writeTo(bb);
+ byte[] flowAddBytes = new byte[bb.readableBytes()];
+ bb.readBytes(flowAddBytes);
+
+ OFErrorCauseData emptyCause = OFErrorCauseData.of(flowAddBytes, OFVersion.OF_13);
+ assertThat(emptyCause.getData(), equalTo(flowAddBytes));
+ assertThat(emptyCause.getParsedMessage().isPresent(), equalTo(true));
+ assertThat(emptyCause.toString(), Matchers.containsString("OFFlowAdd"));
+ assertThat(emptyCause.toString(), Matchers.containsString("idleTimeout=5"));
+ }
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/OFPortBitMapTest.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/OFPortBitMapTest.java
new file mode 100644
index 0000000..4db84f1
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/OFPortBitMapTest.java
@@ -0,0 +1,71 @@
+package org.projectfloodlight.openflow.types;
+
+import static org.hamcrest.Matchers.contains;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertThat;
+import junit.framework.TestCase;
+
+import org.junit.Test;
+
+public class OFPortBitMapTest extends TestCase {
+ @Test
+ public void testCreateAndIterate() {
+ OFPortBitMap map = OFPortBitMap.ofPorts(OFPort.of(1), OFPort.of(2), OFPort.of(5));
+
+ assertThat(map.getOnPorts(), contains(OFPort.of(1), OFPort.of(2), OFPort.of(5)));
+ }
+
+ @Test
+ public void testOFBitMap() {
+ OFBitMask128 bitmap = OFBitMask128.of(0xFFFF_FFFF_FFFF_FFFFL, 0xFFFF_FFFF_FFFF_FFD9L);
+
+ OFPortBitMap map = OFPortBitMap.of(bitmap);
+
+ assertThat(map.getOnPorts(), contains(OFPort.of(1), OFPort.of(2), OFPort.of(5)));
+ }
+
+ @Test
+ public void testOFPortBitMap() {
+ Boolean[] on = new Boolean[127];
+ for (int i = 0; i < 127; i++) {
+ on[i] = false;
+ }
+
+ OFPortBitMap.Builder builder = new OFPortBitMap.Builder();
+
+ for (int i = 0; i < 127; i += 3) {
+ OFPort p = OFPort.of(i);
+ builder.set(p);
+ on[p.getPortNumber()] = true;
+ }
+
+ // Test that all ports that were added are actually on, and all other ports are off
+ OFPortBitMap portmap = builder.build();
+ //System.out.println(portmap);
+ Boolean[] actual = new Boolean[127];
+ for (int i = 0; i < 127; i++) {
+ actual[i] = false;
+ }
+ for (int i = 0; i < 127; i++) {
+ actual[i] = portmap.isOn(OFPort.of(i));
+ }
+ assertArrayEquals(on, actual);
+
+ // Turn some ports off
+ for (int i = 0; i < 127; i += 7) {
+ on[i] = false;
+ builder.unset(OFPort.of(i));
+ }
+
+ // Test again
+ portmap = builder.build();
+ actual = new Boolean[127];
+ for (int i = 0; i < 127; i++) {
+ actual[i] = false;
+ }
+ for (int i = 0; i < 127; i++) {
+ actual[i] = portmap.isOn(OFPort.of(i));
+ }
+ assertArrayEquals(on, actual);
+ }
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/OFVlanVidMatchTest.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/OFVlanVidMatchTest.java
new file mode 100644
index 0000000..ce6e7a2
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/OFVlanVidMatchTest.java
@@ -0,0 +1,44 @@
+package org.projectfloodlight.openflow.types;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+
+public class OFVlanVidMatchTest {
+ @Test
+ public void testofVlanVid() {
+ assertThat(
+ (int) OFVlanVidMatch.ofVlanVid(VlanVid.ofVlan(1)).getRawVid(),
+ equalTo(0x1001));
+ assertThat(
+ (int) OFVlanVidMatch.ofVlanVid(VlanVid.ofVlan(0xFFF)).getRawVid(),
+ equalTo(0x1FFF));
+ assertThat(OFVlanVidMatch.ofVlanVid(null), equalTo(OFVlanVidMatch.UNTAGGED));
+ assertThat(OFVlanVidMatch.ofVlanVid(VlanVid.NO_MASK),
+ equalTo(OFVlanVidMatch.NO_MASK));
+ // a fully masked VlanVid means "PRESENT" in OFVlanVid
+ // (because a VlanVid always specifies a Vlan)
+ assertThat(OFVlanVidMatch.ofVlanVid(VlanVid.FULL_MASK),
+ equalTo(OFVlanVidMatch.PRESENT));
+ }
+ @Test
+ public void testtoVlanVid() {
+ assertThat(
+ OFVlanVidMatch.ofRawVid((short)0x1001).getVlanVid(),
+ equalTo(VlanVid.ofVlan(1)));
+ assertThat(
+ OFVlanVidMatch.ofRawVid((short)0x1FFF).getVlanVid(),
+ equalTo(VlanVid.ofVlan(0xFFF)));
+ assertThat(OFVlanVidMatch.UNTAGGED.getVlanVid(), CoreMatchers.nullValue());
+ assertThat(
+ OFVlanVidMatch.NO_MASK.getVlanVid(),
+ equalTo(VlanVid.NO_MASK));
+ assertThat(
+ OFVlanVidMatch.PRESENT.getVlanVid(),
+ equalTo(VlanVid.FULL_MASK));
+ }
+
+
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/U128Test.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/U128Test.java
new file mode 100644
index 0000000..fb5cd23
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/U128Test.java
@@ -0,0 +1,182 @@
+package org.projectfloodlight.openflow.types;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import com.google.common.hash.HashCode;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
+
+public class U128Test {
+ @Test
+ public void testPositiveRaws() {
+ assertThat(U128.of(0, 0).getMsb(), equalTo(0L));
+ assertThat(U128.of(0, 0).getLsb(), equalTo(0L));
+
+ assertThat(U128.of(1, 2).getMsb(), equalTo(1L));
+ assertThat(U128.of(1, 2).getLsb(), equalTo(2L));
+ }
+
+ @Test
+ public void testPutTo() {
+ U128 h = U128.of(0x1234_5678_90ab_cdefL,0xdeafbeefdeadbeefL);
+ U128 hSame = U128.of(0x1234_5678_90ab_cdefL,0xdeafbeefdeadbeefL);
+
+ U128 hBothDiff = U128.of(0x1234_5678_90ab_cdefL,0x1234_5678_90ab_cdefL);
+ U128 hMsbDiff = U128.of(0x0234_5678_90ab_cdefL,0xdeafbeefdeadbeefL);
+ U128 hLsbDiff = U128.of(0x1234_5678_90ab_cdefL,0xdeafbeefdeadbeeeL);
+
+ assertThat(hash(h), equalTo(hash(hSame)));
+ assertThat(hash(h), not(hash(hBothDiff)));
+ assertThat(hash(h), not(hash(hMsbDiff)));
+ assertThat(hash(h), not(hash(hLsbDiff)));
+ }
+
+ private HashCode hash(U128 f) {
+ Hasher hash = Hashing.murmur3_128().newHasher();
+ f.putTo(hash);
+ return hash.hash();
+
+ }
+
+ @Test
+ public void testEqualHashCode() {
+ U128 h1 = U128.of(0xdeafbeefdeadbeefL, 0xdeafbeefdeadbeefL);
+ U128 h2 = U128.of(0xdeafbeefdeadbeefL, 0xdeafbeefdeadbeefL);
+ U128 h3 = U128.of(0xeeafbeefdeadbeefL, 0xdeafbeefdeadbeefL);
+ U128 h3_2 = U128.of(0xdeafbeefdeadbeefL, 0xeeafbeefdeadbeefL);
+
+ assertTrue(h1.equals(h1));
+ assertTrue(h1.equals(h2));
+ assertFalse(h1.equals(h3));
+ assertFalse(h1.equals(h3_2));
+ assertTrue(h2.equals(h1));
+
+ assertEquals(h1.hashCode(), h2.hashCode());
+ assertNotEquals(h1.hashCode(), h3.hashCode()); // not technically a requirement, but we'll hopefully be lucky.
+ assertNotEquals(h1.hashCode(), h3_2.hashCode()); // not technically a requirement, but we'll hopefully be lucky.
+ }
+
+ @Test
+ public void testXor() {
+ U128 hNull = U128.of(0, 0);
+ U128 hDeadBeef = U128.of(0xdeafbeefdeadbeefL, 0xdeafbeefdeadbeefL);
+ assertThat(hNull.xor(hNull), equalTo(hNull));
+ assertThat(hNull.xor(hDeadBeef), equalTo(hDeadBeef));
+ assertThat(hDeadBeef.xor(hNull), equalTo(hDeadBeef));
+ assertThat(hDeadBeef.xor(hDeadBeef), equalTo(hNull));
+
+
+ U128 h1_0 = U128.of(1L, 0);
+ U128 h8_0 = U128.of(0x8000000000000000L, 0);
+ U128 h81_0 = U128.of(0x8000000000000001L, 0);
+ assertThat(h1_0.xor(h8_0), equalTo(h81_0));
+
+ U128 h0_1 = U128.of(0, 1L);
+ U128 h0_8 = U128.of(0, 0x8000000000000000L);
+ U128 h0_81 = U128.of(0, 0x8000000000000001L);
+ assertThat(h0_1.xor(h0_8), equalTo(h0_81));
+ }
+
+ @Test
+ public void testKeyBits() {
+ U128 zeroU = U128.of(0,0);
+ assertThat(zeroU.prefixBits(0), equalTo(0));
+ assertThat(zeroU.prefixBits(16), equalTo(0));
+ assertThat(zeroU.prefixBits(32), equalTo(0));
+
+ checkInvalidKeyBitSize(zeroU, 33);
+ checkInvalidKeyBitSize(zeroU, 64);
+ assertThat(zeroU.prefixBits(3), equalTo(0));
+
+ U128 positiveU = U128.of(0x1234_5678_1234_5678L, 0x1234_5678_1234_5678L);
+ assertThat(positiveU.prefixBits(0), equalTo(0));
+ assertThat(positiveU.prefixBits(16), equalTo(0x1234));
+ assertThat(positiveU.prefixBits(32), equalTo(0x12345678));
+ checkInvalidKeyBitSize(positiveU, 33);
+ checkInvalidKeyBitSize(positiveU, 64);
+
+ U128 signedBitU = U128.of(0x8765_4321_8765_4321L, 0x1234_5678_1234_5678L);
+ assertThat(signedBitU.prefixBits(0), equalTo(0));
+ assertThat(signedBitU.prefixBits(16), equalTo(0x8765));
+ assertThat(signedBitU.prefixBits(32), equalTo(0x8765_4321));
+ checkInvalidKeyBitSize(signedBitU, 33);
+ checkInvalidKeyBitSize(signedBitU, 64);
+ }
+
+ private void
+ checkInvalidKeyBitSize(U128 u, int prefixBit) {
+ try {
+ u.prefixBits(prefixBit);
+ fail("Expected exception not thrown for "+prefixBit + " bits");
+ } catch(IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+
+ @Test
+ public void testCompare() {
+ U128 u0_0 = U128.of(0, 0);
+ U128 u0_1 = U128.of(0, 1);
+ U128 u0_8 = U128.of(0, 0x8765_4321_8765_4321L);
+ U128 u1_0 = U128.of(0x1234_5678_1234_5678L, 0);
+ U128 u8_0 = U128.of(0x8765_4321_8765_4321L, 0);
+ U128 uf_0 = U128.of(0xFFFF_FFFF_FFFF_FFFFL, 0);
+
+ U128[] us = new U128[] { u0_0, u0_1, u0_8, u1_0, u8_0, uf_0 };
+
+ for(int i = 0; i< us.length; i++) {
+ U128 u_base = us[i];
+ assertThat(
+ String.format("%s should be equal to itself (compareTo)", u_base),
+ u_base.compareTo(u_base), equalTo(0));
+ assertThat(
+ String.format("%s should be equal to itself (equals)", u_base),
+ u_base.equals(u_base), equalTo(true));
+ assertThat(
+ String.format("%s should be equal to itself (equals, by value)", u_base),
+ u_base.equals(U128.of(u_base.getMsb(), u_base.getLsb())), equalTo(true));
+
+ for(int j = i+1; j< us.length; j++) {
+ U128 u_greater = us[j];
+ assertThat(
+ String.format("%s should not be equal to %s", u_base, u_greater),
+ u_base.equals(u_base), equalTo(true));
+ assertThat(
+ String.format("%s should be smaller than %s", u_base, u_greater),
+ u_base.compareTo(u_greater), Matchers.lessThan(0));
+ assertThat(
+ String.format("%s should be greater than %s", u_greater, u_base),
+ u_greater.compareTo(u_base), Matchers.greaterThan(0));
+ }
+ }
+ }
+
+ @Test
+ public void testCombine() {
+ long key = 0x1234567890abcdefL;
+ long val = 0xdeafbeefdeadbeefL;
+ U128 hkey = U128.of(key, key*2);
+ U128 hVal = U128.of(val, val/2);
+
+ assertThat(hkey.combineWithValue(hVal, 0), equalTo(hkey.xor(hVal)));
+ assertThat(hkey.combineWithValue(hVal, 64), equalTo(U128.of(hkey.getMsb(), hkey.getLsb() ^ hVal.getLsb())));
+ assertThat(hkey.combineWithValue(hVal, 128), equalTo(hkey));
+
+ long mask8 = 0xFF00_0000_0000_0000L;
+
+ assertThat(hkey.combineWithValue(hVal, 8), equalTo(U128.of(hkey.getMsb() & mask8 | hkey.getMsb() ^ hVal.getMsb() & ~mask8,
+ hkey.getLsb() ^ hVal.getLsb() )));
+ }
+
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/types/U64Test.java b/of/lib/src/test/java/org/projectfloodlight/openflow/types/U64Test.java
new file mode 100644
index 0000000..b0cca23
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/types/U64Test.java
@@ -0,0 +1,118 @@
+package org.projectfloodlight.openflow.types;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.math.BigInteger;
+
+import org.junit.Test;
+
+public class U64Test {
+
+ @Test
+ public void testPositiveRaws() {
+ for(long positive: new long[] { 0, 1, 100, Long.MAX_VALUE }) {
+ assertEquals(positive, U64.ofRaw(positive).getValue());
+ assertEquals(BigInteger.valueOf(positive), U64.ofRaw(positive).getBigInteger());
+ }
+ }
+
+ @Test
+ public void testNegativeRaws() {
+ long minus_1 = 0xFFFF_FFFF_FFFF_FFFFL;
+ assertEquals(minus_1, U64.ofRaw(minus_1).getValue());
+ assertEquals(new BigInteger("FFFF_FFFF_FFFF_FFFF".replace("_", ""), 16), U64.ofRaw(minus_1).getBigInteger());
+ assertEquals(new BigInteger("18446744073709551615"), U64.ofRaw(minus_1).getBigInteger());
+ }
+
+ @Test
+ public void testEqualHashCode() {
+ U64 h1 = U64.of(0xdeafbeefdeadbeefL);
+ U64 h2 = U64.of(0xdeafbeefdeadbeefL);
+ U64 h3 = U64.of(0xeeafbeefdeadbeefL);
+
+ assertTrue(h1.equals(h1));
+ assertTrue(h1.equals(h2));
+ assertFalse(h1.equals(h3));
+ assertTrue(h2.equals(h1));
+
+ assertEquals(h1.hashCode(), h2.hashCode());
+ assertNotEquals(h1.hashCode(), h3.hashCode()); // not technically a requirement, but we'll hopefully be lucky.
+ }
+
+ @Test
+ public void testXor() {
+ U64 hNull = U64.of(0);
+ U64 hDeadBeef = U64.of(0xdeafbeefdeadbeefL);
+ assertThat(hNull.xor(hNull), equalTo(hNull));
+ assertThat(hNull.xor(hDeadBeef), equalTo(hDeadBeef));
+ assertThat(hDeadBeef.xor(hNull), equalTo(hDeadBeef));
+ assertThat(hDeadBeef.xor(hDeadBeef), equalTo(hNull));
+
+
+ U64 h1 = U64.of(1L);
+ U64 h8 = U64.of(0x8000000000000000L);
+ U64 h81 = U64.of(0x8000000000000001L);
+ assertThat(h1.xor(h8), equalTo(h81));
+ }
+
+ @Test
+ public void testCombine() {
+ long key = 0x1234567890abcdefL;
+ long val = 0xdeafbeefdeadbeefL;
+ U64 hkey = U64.of(key);
+ U64 hVal = U64.of(val);
+
+ assertThat(hkey.combineWithValue(hVal, 0), equalTo(hkey.xor(hVal)));
+ assertThat(hkey.combineWithValue(hVal, 64), equalTo(hkey));
+ long mask32 = 0x00000000FFFFFFFFL;
+ assertThat(hkey.combineWithValue(hVal, 32),
+ equalTo(U64.of(key & ~mask32| (key ^ val) & mask32)));
+
+ long tenMask = 0x003FFFFFFFFFFFFFL;
+ assertThat(hkey.combineWithValue(hVal, 10),
+ equalTo(U64.of(key & ~tenMask | (key ^ val) & tenMask)));
+ }
+
+ @Test
+ public void testKeyBits() {
+ U64 zeroU = U64.of(0);
+ assertThat(zeroU.prefixBits(0), equalTo(0));
+ assertThat(zeroU.prefixBits(16), equalTo(0));
+ assertThat(zeroU.prefixBits(32), equalTo(0));
+
+ checkInvalidKeyBitSize(zeroU, 33);
+ checkInvalidKeyBitSize(zeroU, 64);
+ assertThat(zeroU.prefixBits(3), equalTo(0));
+
+ U64 positiveU = U64.of(0x1234_5678_1234_5678L);
+ assertThat(positiveU.prefixBits(0), equalTo(0));
+ assertThat(positiveU.prefixBits(16), equalTo(0x1234));
+ assertThat(positiveU.prefixBits(32), equalTo(0x12345678));
+ checkInvalidKeyBitSize(positiveU, 33);
+ checkInvalidKeyBitSize(positiveU, 64);
+
+ U64 signedBitU = U64.of(0x8765_4321_8765_4321L);
+ assertThat(signedBitU.prefixBits(0), equalTo(0));
+ assertThat(signedBitU.prefixBits(16), equalTo(0x8765));
+ assertThat(signedBitU.prefixBits(32), equalTo(0x8765_4321));
+ checkInvalidKeyBitSize(signedBitU, 33);
+ checkInvalidKeyBitSize(signedBitU, 64);
+ }
+
+ private void
+ checkInvalidKeyBitSize(U64 u, int prefixBit) {
+ try {
+ u.prefixBits(prefixBit);
+ fail("Expected exception not thrown for "+prefixBit + " bits");
+ } catch(IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/util/HexStringTest.java b/of/lib/src/test/java/org/projectfloodlight/openflow/util/HexStringTest.java
new file mode 100644
index 0000000..360cb5a6
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/util/HexStringTest.java
@@ -0,0 +1,103 @@
+/**
+* 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
+*
+* 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.projectfloodlight.openflow.util;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+/**
+ * Does hexstring conversion work?
+ *
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+public class HexStringTest {
+
+ @Test
+ public void testMarshalling() throws Exception {
+ String dpidStr = "00:00:00:23:20:2d:16:71";
+ long dpid = HexString.toLong(dpidStr);
+ String testStr = HexString.toHexString(dpid);
+ assertEquals(dpidStr, testStr);
+ }
+
+ @Test
+ public void testToLong() {
+ String dpidStr = "3e:1f:01:fc:72:8c:63:31";
+ long valid = 0x3e1f01fc728c6331L;
+ long testLong = HexString.toLong(dpidStr);
+ assertEquals(valid, testLong);
+ }
+
+ @Test
+ public void testToLong2() {
+ String dpidStr = "1f:1:fc:72:3:f:31";
+ long valid = 0x1f01fc72030f31L;
+ long testLong = HexString.toLong(dpidStr);
+ assertEquals(valid, testLong);
+ }
+
+ @Test
+ public void testToLongMSB() {
+ String dpidStr = "ca:7c:5e:d1:64:7a:95:9b";
+ long valid = -3856102927509056101L;
+ long testLong = HexString.toLong(dpidStr);
+ assertEquals(valid, testLong);
+ }
+
+ @Test(expected=NumberFormatException.class)
+ public void testToLongErrorTooManyBytes() {
+ HexString.toLong("09:08:07:06:05:04:03:02:01");
+ }
+
+ @Test(expected=NumberFormatException.class)
+ public void testToLongErrorByteValueTooLong() {
+ HexString.toLong("234:01");
+ }
+
+ @Test(expected=NumberFormatException.class)
+ public void testToLongErrorEmptyByte() {
+ HexString.toLong("03::01");
+ }
+
+ @Test(expected=NumberFormatException.class)
+ public void testToLongErrorInvalidHexDigit() {
+ HexString.toLong("ss:01");
+ }
+
+ @Test(expected=NumberFormatException.class)
+ public void testToLongErrorEmptyString() {
+ HexString.toLong("");
+ }
+
+
+ @Test
+ public void testToStringBytes() {
+ byte[] dpid = { 0, 0, 0, 0, 0, 0, 0, -1 };
+ String valid = "00:00:00:00:00:00:00:ff";
+ String testString = HexString.toHexString(dpid);
+ assertEquals(valid, testString);
+ }
+
+ @Test(expected=NumberFormatException.class)
+ public void testFromHexStringError() {
+ String invalidStr = "00:00:00:00:00:00:ffff";
+ HexString.fromHexString(invalidStr);
+ }
+}
+
diff --git a/of/lib/src/test/java/org/projectfloodlight/openflow/util/PrimitiveSinkUtilsTest.java b/of/lib/src/test/java/org/projectfloodlight/openflow/util/PrimitiveSinkUtilsTest.java
new file mode 100644
index 0000000..f5bf3e4
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/openflow/util/PrimitiveSinkUtilsTest.java
@@ -0,0 +1,130 @@
+package org.projectfloodlight.openflow.util;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+
+import java.util.Arrays;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.PrimitiveSinkable;
+
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.hash.HashCode;
+import com.google.common.hash.HashFunction;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
+
+public class PrimitiveSinkUtilsTest {
+
+ private HashFunction hash;
+
+ @Before
+ public void setup() {
+ hash = Hashing.murmur3_128();
+ }
+
+ @Test
+ public void testPutNullableString() {
+ // test that these different invocations of putNullable
+ // differ pairwise
+ HashCode[] hs = new HashCode[] {
+ calcPutNullableString((String) null),
+ calcPutNullableString(""),
+ calcPutNullableString(null, null),
+ calcPutNullableString(null, ""),
+ calcPutNullableString("", null),
+ calcPutNullableString("a\0a", null),
+ calcPutNullableString(null, "a\0a"),
+ };
+
+ checkPairwiseDifferent(hs);
+ }
+
+ @Test
+ public void testPutNullable() {
+ // test that these different invocations of putNullable
+ // differ pairwise
+ HashCode[] hs = new HashCode[] {
+ calcPutNullables(),
+ calcPutNullables(OFPort.of(1)),
+ calcPutNullables(OFPort.of(1), null),
+ calcPutNullables(OFPort.of(1), null, null),
+ calcPutNullables(null, OFPort.of(1), null),
+ calcPutNullables(null, null, OFPort.of(1))
+ };
+
+ checkPairwiseDifferent(hs);
+ }
+
+ private void checkPairwiseDifferent(HashCode[] hs) {
+ for(int i=0;i<hs.length;i++) {
+ for(int j=i+1; j<hs.length;j++) {
+ assertThat(hs[i], not(hs[j]));
+ }
+ }
+ }
+
+ @Test
+ public void testPutList() {
+ HashCode[] hs = new HashCode[] {
+ calcPutList(),
+ calcPutList(OFPort.of(1)),
+ calcPutList(OFPort.of(2)),
+ calcPutList(OFPort.of(1), OFPort.of(2)),
+ calcPutList(OFPort.of(2), OFPort.of(1)),
+ calcPutList(OFPort.of(1), OFPort.of(3)),
+ calcPutList(OFPort.of(1), OFPort.of(2), OFPort.of(3)),
+ };
+
+ checkPairwiseDifferent(hs);
+ }
+
+ @Test
+ public void testPutSortedSet() {
+ HashCode[] hs = new HashCode[] {
+ calcPutSortedSet(),
+ calcPutSortedSet(OFPort.of(1)),
+ calcPutSortedSet(OFPort.of(2)),
+ calcPutSortedSet(OFPort.of(1), OFPort.of(2)),
+ calcPutSortedSet(OFPort.of(1), OFPort.of(3)),
+ calcPutSortedSet(OFPort.of(1), OFPort.of(2), OFPort.of(3)),
+ };
+
+ checkPairwiseDifferent(hs);
+
+ assertThat(calcPutSortedSet(OFPort.of(1), OFPort.of(2)),
+ equalTo(calcPutSortedSet(OFPort.of(2), OFPort.of(1))));
+ }
+
+ private HashCode calcPutNullableString(String... strings) {
+ Hasher h = hash.newHasher();
+ for(String s: strings) {
+ PrimitiveSinkUtils.putNullableStringTo(h, s);
+ }
+ return h.hash();
+ }
+
+ private HashCode calcPutSortedSet(OFPort... ports) {
+ Hasher h = hash.newHasher();
+ PrimitiveSinkUtils.putSortedSetTo(h, ImmutableSortedSet.copyOf(ports));
+ return h.hash();
+ }
+
+ private HashCode calcPutList(OFPort... ports) {
+ Hasher h = hash.newHasher();
+ PrimitiveSinkUtils.putListTo(h, Arrays.asList(ports));
+ return h.hash();
+ }
+
+
+ private HashCode calcPutNullables(PrimitiveSinkable... ps) {
+ Hasher h = hash.newHasher();
+ for(PrimitiveSinkable p : ps) {
+ PrimitiveSinkUtils.putNullableTo(h, p);
+ }
+ return h.hash();
+ }
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/protocol/OFOxmListTest.java b/of/lib/src/test/java/org/projectfloodlight/protocol/OFOxmListTest.java
new file mode 100644
index 0000000..39e8c0c
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/protocol/OFOxmListTest.java
@@ -0,0 +1,41 @@
+package org.projectfloodlight.protocol;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+
+import org.hamcrest.CoreMatchers;
+import org.junit.Before;
+import org.junit.Test;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFOxmList;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv6DstMasked;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv6SrcMasked;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxms;
+import org.projectfloodlight.openflow.types.IPv6AddressWithMask;
+
+public class OFOxmListTest {
+ private OFOxms oxms;
+
+ @Before
+ public void setup() {
+ oxms = OFFactories.getFactory(OFVersion.OF_13).oxms();
+ }
+
+ @Test
+ public void testCanonicalize() {
+ OFOxmList.Builder builder = new OFOxmList.Builder();
+ IPv6AddressWithMask fullMasked = IPv6AddressWithMask.of("::/0");
+ OFOxmIpv6DstMasked fullMaskedOxm = oxms.ipv6DstMasked(fullMasked.getValue(), fullMasked.getMask());
+ builder.set(fullMaskedOxm);
+
+ IPv6AddressWithMask address= IPv6AddressWithMask.of("1:2:3:4:5:6::8");
+ OFOxmIpv6SrcMasked addressSrcOxm = oxms.ipv6SrcMasked(address.getValue(), address.getMask());
+ builder.set(addressSrcOxm);
+
+ OFOxmList list = builder.build();
+ assertThat(list.get(MatchField.IPV6_DST), CoreMatchers.nullValue());
+ assertFalse(list.get(MatchField.IPV6_SRC).isMasked());
+ }
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/protocol/OFOxmTest.java b/of/lib/src/test/java/org/projectfloodlight/protocol/OFOxmTest.java
new file mode 100644
index 0000000..8482886
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/protocol/OFOxmTest.java
@@ -0,0 +1,62 @@
+package org.projectfloodlight.protocol;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import org.hamcrest.CoreMatchers;
+import org.junit.Before;
+import org.junit.Test;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4Src;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4SrcMasked;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxms;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IPv4AddressWithMask;
+
+public class OFOxmTest {
+ private OFOxms oxms;
+
+ @Before
+ public void setup() {
+ oxms = OFFactories.getFactory(OFVersion.OF_13).oxms();
+ }
+
+ @Test
+ public void testGetCanonicalFullMask() {
+ IPv4AddressWithMask empty = IPv4AddressWithMask.of("0.0.0.0/0");
+ assertEquals(IPv4Address.FULL_MASK, empty.getMask());
+ OFOxmIpv4SrcMasked ipv4SrcMasked = oxms.ipv4SrcMasked(empty.getValue(), empty.getMask());
+ // canonicalize should remove /0
+ assertNull(ipv4SrcMasked.getCanonical());
+ }
+
+ @Test
+ public void testGetCanonicalNoMask() {
+ IPv4AddressWithMask fullIp = IPv4AddressWithMask.of("1.2.3.4/32");
+ assertEquals(IPv4Address.NO_MASK, fullIp.getMask());
+ OFOxmIpv4SrcMasked ipv4SrcMasked = oxms.ipv4SrcMasked(fullIp.getValue(), fullIp.getMask());
+ assertTrue(ipv4SrcMasked.isMasked());
+ assertEquals(IPv4Address.NO_MASK, ipv4SrcMasked.getMask());
+
+ // canonicalize should convert the masked oxm to the non-masked one
+ OFOxm<IPv4Address> canonical = ipv4SrcMasked.getCanonical();
+ assertThat(canonical, CoreMatchers.instanceOf(OFOxmIpv4Src.class));
+ assertFalse(canonical.isMasked());
+ }
+
+ @Test
+ public void testGetCanonicalNormalMask() {
+ IPv4AddressWithMask ip = IPv4AddressWithMask.of("1.2.3.0/24");
+ OFOxmIpv4SrcMasked ipv4SrcMasked = oxms.ipv4SrcMasked(ip.getValue(), ip.getMask());
+ assertTrue(ipv4SrcMasked.isMasked());
+
+ // canonicalize should convert the masked oxm to the non-masked one
+ OFOxm<IPv4Address> canonical = ipv4SrcMasked.getCanonical();
+ assertEquals(ipv4SrcMasked, canonical);
+ }
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIteration10Test.java b/of/lib/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIteration10Test.java
new file mode 100644
index 0000000..c6f4471
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIteration10Test.java
@@ -0,0 +1,10 @@
+package org.projectfloodlight.protocol.match;
+
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+
+public class MatchFieldIteration10Test extends MatchFieldIterationBase {
+ public MatchFieldIteration10Test() {
+ super(OFFactories.getFactory(OFVersion.OF_10));
+ }
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIteration13Test.java b/of/lib/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIteration13Test.java
new file mode 100644
index 0000000..b654a53
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIteration13Test.java
@@ -0,0 +1,10 @@
+package org.projectfloodlight.protocol.match;
+
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+
+public class MatchFieldIteration13Test extends MatchFieldIterationBase {
+ public MatchFieldIteration13Test() {
+ super(OFFactories.getFactory(OFVersion.OF_13));
+ }
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIterationBase.java b/of/lib/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIterationBase.java
new file mode 100644
index 0000000..9c72e37
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIterationBase.java
@@ -0,0 +1,249 @@
+package org.projectfloodlight.protocol.match;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+import java.util.Iterator;
+
+import org.junit.Test;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.match.MatchFields;
+import org.projectfloodlight.openflow.types.ArpOpcode;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.Masked;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TransportPort;
+
+import com.google.common.collect.Iterables;
+
+public class MatchFieldIterationBase {
+
+ private OFFactory factory;
+
+ protected MatchFieldIterationBase(OFFactory factory) {
+ this.factory = factory;
+ }
+
+ @Test
+ public void iterateEmptyMatch() {
+ Match match = factory.buildMatch().build();
+ Iterator<MatchField<?>> iter = match.getMatchFields().iterator();
+ assertThat(iter.hasNext(), is(false));
+ }
+
+ @Test
+ public void iterateSingleExactMatchField() {
+ OFPort port5 = OFPort.of(5);
+ Match match = factory.buildMatch()
+ .setExact(MatchField.IN_PORT, port5)
+ .build();
+ Iterator<MatchField<?>> iter = match.getMatchFields().iterator();
+ assertThat(iter.hasNext(), is(true));
+ MatchField<?> matchField = iter.next();
+ assertThat(matchField.id, is(MatchFields.IN_PORT));
+ assertThat(match.isExact(matchField), is(true));
+ @SuppressWarnings("unchecked")
+ MatchField<OFPort> portMatchField = (MatchField<OFPort>) matchField;
+ OFPort port = match.get(portMatchField);
+ assertThat(port, is(port5));
+ assertThat(iter.hasNext(), is(false));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void iterateExactMatchFields() {
+ OFPort port5 = OFPort.of(5);
+ MacAddress macSrc = MacAddress.of("00:01:02:03:04:05");
+ MacAddress macDst = MacAddress.of("01:01:02:02:03:03");
+ IPv4Address ipSrc = IPv4Address.of("10.192.20.1");
+ IPv4Address ipDst = IPv4Address.of("10.192.20.2");
+ TransportPort tcpSrc = TransportPort.of(100);
+ TransportPort tcpDst = TransportPort.of(200);
+ Match match = factory.buildMatch()
+ .setExact(MatchField.IN_PORT, port5)
+ .setExact(MatchField.ETH_TYPE, EthType.IPv4)
+ .setExact(MatchField.ETH_SRC, macSrc)
+ .setExact(MatchField.ETH_DST, macDst)
+ .setExact(MatchField.IP_PROTO, IpProtocol.TCP)
+ .setExact(MatchField.IPV4_SRC, ipSrc)
+ .setExact(MatchField.IPV4_DST, ipDst)
+ .setExact(MatchField.TCP_SRC, tcpSrc)
+ .setExact(MatchField.TCP_DST, tcpDst)
+ .build();
+ assertThat(Iterables.size(match.getMatchFields()), is(9));
+ for (MatchField<?> matchField: match.getMatchFields()) {
+ switch (matchField.id) {
+ case IN_PORT:
+ OFPort port = match.get((MatchField<OFPort>) matchField);
+ assertThat(port, is(port5));
+ break;
+ case ETH_TYPE:
+ EthType ethType = match.get((MatchField<EthType>) matchField);
+ assertThat(ethType, is(EthType.IPv4));
+ break;
+ case ETH_SRC:
+ MacAddress mac = match.get((MatchField<MacAddress>) matchField);
+ assertThat(mac, is(macSrc));
+ break;
+ case ETH_DST:
+ mac = match.get((MatchField<MacAddress>) matchField);
+ assertThat(mac, is(macDst));
+ break;
+ case IP_PROTO:
+ IpProtocol ipProtocol = match.get((MatchField<IpProtocol>) matchField);
+ assertThat(ipProtocol, is(IpProtocol.TCP));
+ break;
+ case IPV4_SRC:
+ IPv4Address ip = match.get((MatchField<IPv4Address>) matchField);
+ assertThat(ip, is(ipSrc));
+ break;
+ case IPV4_DST:
+ ip = match.get((MatchField<IPv4Address>) matchField);
+ assertThat(ip, is(ipDst));
+ break;
+ case TCP_SRC:
+ TransportPort tcp = match.get((MatchField<TransportPort>) matchField);
+ assertThat(tcp, is(tcpSrc));
+ break;
+ case TCP_DST:
+ tcp = match.get((MatchField<TransportPort>) matchField);
+ assertThat(tcp, is(tcpDst));
+ break;
+ default:
+ fail("Unexpected match field returned from iterator");
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void iterateArpFields() {
+ MacAddress macSrc = MacAddress.of("00:01:02:03:04:05");
+ MacAddress macDst = MacAddress.of("01:01:02:02:03:03");
+ IPv4Address ipSrc = IPv4Address.of("10.192.20.1");
+ IPv4Address ipDst = IPv4Address.of("10.192.20.2");
+ OFVersion version = factory.getVersion();
+ boolean supportsArpHardwareAddress = (version != OFVersion.OF_10) &&
+ (version != OFVersion.OF_11) && (version != OFVersion.OF_12);
+ int matchFieldCount = 4;
+ Match.Builder builder = factory.buildMatch();
+ builder.setExact(MatchField.ETH_TYPE, EthType.ARP)
+ .setExact(MatchField.ARP_OP, ArpOpcode.REPLY)
+ .setExact(MatchField.ARP_SPA, ipSrc)
+ .setExact(MatchField.ARP_TPA, ipDst);
+ if (supportsArpHardwareAddress) {
+ builder.setExact(MatchField.ARP_SHA, macSrc);
+ builder.setExact(MatchField.ARP_THA, macDst);
+ matchFieldCount += 2;
+ }
+ Match match = builder.build();
+ assertThat(Iterables.size(match.getMatchFields()), is(matchFieldCount));
+ for (MatchField<?> matchField: match.getMatchFields()) {
+ switch (matchField.id) {
+ case ETH_TYPE:
+ EthType ethType = match.get((MatchField<EthType>) matchField);
+ assertThat(ethType, is(EthType.ARP));
+ break;
+ case ARP_OP:
+ ArpOpcode opcode = match.get((MatchField<ArpOpcode>) matchField);
+ assertThat(opcode, is(ArpOpcode.REPLY));
+ break;
+ case ARP_SHA:
+ MacAddress mac = match.get((MatchField<MacAddress>) matchField);
+ assertThat(mac, is(macSrc));
+ break;
+ case ARP_THA:
+ mac = match.get((MatchField<MacAddress>) matchField);
+ assertThat(mac, is(macDst));
+ break;
+ case ARP_SPA:
+ IPv4Address ip = match.get((MatchField<IPv4Address>) matchField);
+ assertThat(ip, is(ipSrc));
+ break;
+ case ARP_TPA:
+ ip = match.get((MatchField<IPv4Address>) matchField);
+ assertThat(ip, is(ipDst));
+ break;
+ default:
+ fail("Unexpected match field returned from iterator");
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void iterateMaskedFields() {
+ MacAddress macSrc = MacAddress.of("01:02:03:04:00:00");
+ MacAddress macSrcMask = MacAddress.of("FF:FF:FF:FF:00:00");
+ MacAddress macDst = MacAddress.of("11:22:33:00:00:00");
+ MacAddress macDstMask = MacAddress.of("FF:FF:FF:00:00:00");
+ IPv4Address ipSrc = IPv4Address.of("10.192.20.0");
+ IPv4Address ipSrcMask = IPv4Address.of("255.255.255.0");
+ IPv4Address ipDst = IPv4Address.of("10.192.20.0");
+ IPv4Address ipDstMask = IPv4Address.of("255.255.255.128");
+ TransportPort tcpSrcMask = TransportPort.of(0x01F0);
+ OFVersion version = factory.getVersion();
+ boolean supportsAllMasks = (version != OFVersion.OF_10) &&
+ (version != OFVersion.OF_11) && (version != OFVersion.OF_12);
+ int matchFieldCount = 4;
+ Match.Builder builder = factory.buildMatch()
+ .setExact(MatchField.ETH_TYPE, EthType.IPv4)
+ .setMasked(MatchField.IPV4_SRC, ipSrc, ipSrcMask)
+ .setMasked(MatchField.IPV4_DST, ipDst, ipDstMask)
+ .setExact(MatchField.IP_PROTO, IpProtocol.TCP);
+ if (supportsAllMasks) {
+ builder.setMasked(MatchField.ETH_SRC, macSrc, macSrcMask);
+ builder.setMasked(MatchField.ETH_DST, macDst, macDstMask);
+ builder.setMasked(MatchField.TCP_SRC, tcpSrcMask, tcpSrcMask);
+ matchFieldCount += 3;
+ }
+ Match match = builder.build();
+ assertThat(Iterables.size(match.getMatchFields()), is(matchFieldCount));
+ for (MatchField<?> matchField: match.getMatchFields()) {
+ switch (matchField.id) {
+ case ETH_TYPE:
+ EthType ethType = match.get((MatchField<EthType>) matchField);
+ assertThat(ethType, is(EthType.IPv4));
+ break;
+ case ETH_SRC:
+ Masked<MacAddress> mac = match.getMasked((MatchField<MacAddress>) matchField);
+ assertThat(mac.getValue(), is(macSrc));
+ assertThat(mac.getMask(), is(macSrcMask));
+ break;
+ case ETH_DST:
+ mac = match.getMasked((MatchField<MacAddress>) matchField);
+ assertThat(mac.getValue(), is(macDst));
+ assertThat(mac.getMask(), is(macDstMask));
+ break;
+ case IP_PROTO:
+ IpProtocol ipProtocol = match.get((MatchField<IpProtocol>) matchField);
+ assertThat(ipProtocol, is(IpProtocol.TCP));
+ break;
+ case IPV4_SRC:
+ Masked<IPv4Address> ip = match.getMasked((MatchField<IPv4Address>) matchField);
+ assertThat(ip.getValue(), is(ipSrc));
+ assertThat(ip.getMask(), is(ipSrcMask));
+ break;
+ case IPV4_DST:
+ ip = match.getMasked((MatchField<IPv4Address>) matchField);
+ assertThat(ip.getValue(), is(ipDst));
+ assertThat(ip.getMask(), is(ipDstMask));
+ break;
+ case TCP_SRC:
+ Masked<TransportPort> tcp = match.getMasked((MatchField<TransportPort>) matchField);
+ assertThat(tcp.getValue(), is(tcpSrcMask));
+ assertThat(tcp.getMask(), is(tcpSrcMask));
+ break;
+ default:
+ fail("Unexpected match field returned from iterator");
+ }
+ }
+ }
+}
diff --git a/of/lib/src/test/java/org/projectfloodlight/test/TestUtils.java b/of/lib/src/test/java/org/projectfloodlight/test/TestUtils.java
new file mode 100644
index 0000000..7a5b8b0
--- /dev/null
+++ b/of/lib/src/test/java/org/projectfloodlight/test/TestUtils.java
@@ -0,0 +1,62 @@
+package org.projectfloodlight.test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.common.primitives.Bytes;
+
+public class TestUtils {
+ private TestUtils() {}
+
+ private static final int PER_LINE = 8;
+
+ public static void betterAssertArrayEquals(byte[] expected, byte[] got) {
+ int maxlen = Math.max(expected.length, got.length);
+
+ List<String> expectedList = formatHex(Bytes.asList(expected));
+ List<String> gotList = formatHex(Bytes.asList(got));
+
+ boolean fail = false;
+ for (int i = 0; i < maxlen;i+= PER_LINE) {
+ int maxThisLine = Math.min(maxlen, PER_LINE);
+ boolean print = false;
+
+ ArrayList<String> changeMarkers = new ArrayList<String>();
+
+ for (int j = i; j < maxThisLine; j++) {
+ if (j >= expected.length || j >= got.length || expected[j] != got[j]) {
+ print = true;
+ fail = true;
+ changeMarkers.add("==");
+ break;
+ } else {
+ changeMarkers.add(" ");
+ }
+ }
+ if(print) {
+ System.out.println(String.format("%4x: %s", i, Joiner.on(" ").join(expectedList.subList(i, Math.min(expectedList.size(), i+PER_LINE)))));
+ System.out.println(String.format("%4x: %s", i, Joiner.on(" ").join(gotList.subList(i, Math.min(gotList.size(), i+PER_LINE)))));
+ System.out.println(String.format("%4s %s", "", Joiner.on(" ").join(changeMarkers)));
+ System.out.println("\n");
+ }
+ }
+ if(fail) {
+ Assert.fail("Array comparison failed");
+ }
+
+ }
+
+ private static List<String> formatHex(List<Byte> b) {
+ return Lists.transform(b, new Function<Byte, String>() {
+ @Override
+ public String apply(Byte input) {
+ return String.format("%02x", input);
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/of/lib/src/test/resources/logback-test.xml b/of/lib/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..e759962
--- /dev/null
+++ b/of/lib/src/test/resources/logback-test.xml
@@ -0,0 +1,13 @@
+<configuration scan="true">
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%d{HH:mm:ss.SSS} %level [%logger{20}:%thread] %msg%n</pattern>
+ </encoder>
+ </appender>
+ <root level="INFO">
+ <appender-ref ref="STDOUT" />
+ </root>
+ <logger name="org" level="WARN"/>
+ <logger name="LogService" level="WARN"/> <!-- Restlet access logging -->
+ <logger name="org.projectfloodlight.openflow" level="DEBUG"/>
+</configuration>