diff --git a/build.xml b/build.xml
index 6d67ce6ea241b1e5ed82231b239aa86a7e5585a4..a430867363dfacede2ee55be60f7af9389a72113 100644
--- a/build.xml
+++ b/build.xml
@@ -53,13 +53,14 @@
     <patternset id="lib">
         <include name="logback-classic-1.0.0.jar"/>
         <include name="logback-core-1.0.0.jar"/>
-        <include name="jackson-core-2.1.4.jar"/>
-        <include name="jackson-annotations-2.1.4.jar"/>
-        <include name="jackson-databind-2.1.4.jar"/>
-        <include name="jackson-dataformat-smile-2.1.4.jar"/>
-        <include name="jackson-dataformat-xml-2.1.4.jar"/>
-        <include name="jackson-dataformat-yaml-2.1.4.jar"/>
-        <include name="jackson-dataformat-csv-2.1.4.jar"/>
+        <include name="jackson-core-2.4.4.jar"/>
+        <include name="jackson-annotations-2.4.4.jar"/>
+        <include name="jackson-databind-2.4.4.jar"/>
+        <include name="jackson-dataformat-smile-2.4.4.jar"/>
+        <include name="jackson-dataformat-xml-2.4.4.jar"/>
+        <include name="jackson-dataformat-yaml-2.4.4.jar"/>
+        <include name="jackson-dataformat-csv-2.4.4.jar"/>
+        <include name="jackson-dataformat-cbor-2.4.4.jar"/>
         <include name="slf4j-api-1.6.4.jar"/>
         <include name="org.restlet.jar"/>
         <include name="org.restlet.ext.jackson.jar"/>
diff --git a/lib/jackson-annotations-2.1.4.jar b/lib/jackson-annotations-2.1.4.jar
deleted file mode 100644
index 143edf44b0daa4cef1a452ecccac21aee22a8d77..0000000000000000000000000000000000000000
Binary files a/lib/jackson-annotations-2.1.4.jar and /dev/null differ
diff --git a/lib/jackson-annotations-2.4.4.jar b/lib/jackson-annotations-2.4.4.jar
new file mode 100644
index 0000000000000000000000000000000000000000..4779188a9f0f306169d566bf7e73570e0bf3e45b
Binary files /dev/null and b/lib/jackson-annotations-2.4.4.jar differ
diff --git a/lib/jackson-core-2.1.4.jar b/lib/jackson-core-2.1.4.jar
deleted file mode 100644
index 0f144685f7140d2694eeba5609322b4cd79f0bf8..0000000000000000000000000000000000000000
Binary files a/lib/jackson-core-2.1.4.jar and /dev/null differ
diff --git a/lib/jackson-core-2.4.4.jar b/lib/jackson-core-2.4.4.jar
new file mode 100644
index 0000000000000000000000000000000000000000..da2a877f186a999df8fbafaac5c59316d3fb70b4
Binary files /dev/null and b/lib/jackson-core-2.4.4.jar differ
diff --git a/lib/jackson-databind-2.1.4.jar b/lib/jackson-databind-2.1.4.jar
deleted file mode 100644
index ce125d1df292a1d8fa4b86cf39770d0d9c4636cc..0000000000000000000000000000000000000000
Binary files a/lib/jackson-databind-2.1.4.jar and /dev/null differ
diff --git a/lib/jackson-databind-2.4.4.jar b/lib/jackson-databind-2.4.4.jar
new file mode 100644
index 0000000000000000000000000000000000000000..e945e5e800666e0c5f99e9571185327f663d73ce
Binary files /dev/null and b/lib/jackson-databind-2.4.4.jar differ
diff --git a/lib/jackson-dataformat-cbor-2.4.4.jar b/lib/jackson-dataformat-cbor-2.4.4.jar
new file mode 100644
index 0000000000000000000000000000000000000000..8a536d2b806a5a50473e602a932f1a2527b3a604
Binary files /dev/null and b/lib/jackson-dataformat-cbor-2.4.4.jar differ
diff --git a/lib/jackson-dataformat-csv-2.1.4.jar b/lib/jackson-dataformat-csv-2.1.4.jar
deleted file mode 100644
index e97503cb161c44ca54d096ec669b707e522f0004..0000000000000000000000000000000000000000
Binary files a/lib/jackson-dataformat-csv-2.1.4.jar and /dev/null differ
diff --git a/lib/jackson-dataformat-csv-2.4.4.jar b/lib/jackson-dataformat-csv-2.4.4.jar
new file mode 100644
index 0000000000000000000000000000000000000000..f561dc10ff44e60210f04315f508bf76d1843d1c
Binary files /dev/null and b/lib/jackson-dataformat-csv-2.4.4.jar differ
diff --git a/lib/jackson-dataformat-smile-2.1.4.jar b/lib/jackson-dataformat-smile-2.1.4.jar
deleted file mode 100644
index e907c7726c5679a572e098293581bba28ac63fa1..0000000000000000000000000000000000000000
Binary files a/lib/jackson-dataformat-smile-2.1.4.jar and /dev/null differ
diff --git a/lib/jackson-dataformat-smile-2.4.4.jar b/lib/jackson-dataformat-smile-2.4.4.jar
new file mode 100644
index 0000000000000000000000000000000000000000..2a6b285190944cd6536619e0caca6aca4af18067
Binary files /dev/null and b/lib/jackson-dataformat-smile-2.4.4.jar differ
diff --git a/lib/jackson-dataformat-xml-2.1.4.jar b/lib/jackson-dataformat-xml-2.1.4.jar
deleted file mode 100644
index 15c82e69c86703363e16d47cb8cb3c3de1919c43..0000000000000000000000000000000000000000
Binary files a/lib/jackson-dataformat-xml-2.1.4.jar and /dev/null differ
diff --git a/lib/jackson-dataformat-xml-2.4.4.jar b/lib/jackson-dataformat-xml-2.4.4.jar
new file mode 100644
index 0000000000000000000000000000000000000000..8f0fa34d09634e02bda7dc0fe7938b8e58fdb1a2
Binary files /dev/null and b/lib/jackson-dataformat-xml-2.4.4.jar differ
diff --git a/lib/jackson-dataformat-yaml-2.1.4.jar b/lib/jackson-dataformat-yaml-2.1.4.jar
deleted file mode 100644
index 444ef88653e9574fb90246679835448e02170ee8..0000000000000000000000000000000000000000
Binary files a/lib/jackson-dataformat-yaml-2.1.4.jar and /dev/null differ
diff --git a/lib/jackson-dataformat-yaml-2.4.4.jar b/lib/jackson-dataformat-yaml-2.4.4.jar
new file mode 100644
index 0000000000000000000000000000000000000000..7770cb918467a8141c8d169f09042a5112e5f36d
Binary files /dev/null and b/lib/jackson-dataformat-yaml-2.4.4.jar differ
diff --git a/pom.xml b/pom.xml
index a77870f01eaa2a1274109da175eb7d650df2e2ea..05c0b1784d45c95844c78a6f0f48256f030475db 100644
--- a/pom.xml
+++ b/pom.xml
@@ -219,9 +219,15 @@
 			<artifactId>netty</artifactId>
 			<version>3.9.0.Final</version>
 		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.dataformat</groupId>
+			<artifactId>jackson-dataformat-cbor</artifactId>
+			<version>${lib-jackson-version}</version>
+		</dependency>
 	</dependencies>
 	<properties>
 		<lib-restlet-version>2.3.2</lib-restlet-version>
+		<lib-jackson-version>2.4.4</lib-jackson-version>
 		<lib-hamcrest-version>1.3</lib-hamcrest-version>
 	</properties>
 </project>
diff --git a/src/main/java/net/floodlightcontroller/packet/SPUD.java b/src/main/java/net/floodlightcontroller/packet/SPUD.java
new file mode 100644
index 0000000000000000000000000000000000000000..d443d59dade46d471a5d75c7799c8e18cc719452
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/packet/SPUD.java
@@ -0,0 +1,153 @@
+package net.floodlightcontroller.packet;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+/**
+ * @author Jacob Chappell (jacob.chappell@uky.edu)
+ */
+public class SPUD extends BasePacket {
+    public static final byte[] MAGIC_CONSTANT =
+        { (byte) 0xd8, 0x00, 0x00, (byte) 0xd8 };
+    public static final int HEADER_LENGTH = 13;
+    public static final byte COMMAND_DATA = 0x0;
+    public static final byte COMMAND_OPEN = 0x1;
+    public static final byte COMMAND_CLOSE = 0x2;
+    public static final byte COMMAND_ACK = 0x3;
+
+    protected long tubeID;
+    protected byte command;
+    protected boolean adec;
+    protected boolean pdec;
+    protected byte reserved;
+
+    public long getTubeID() {
+        return tubeID;
+    }
+
+    public SPUD setTubeID(long tubeID) {
+        this.tubeID = tubeID;
+        return this;
+    }
+
+    public byte getCommand() {
+        return command;
+    }
+
+    public SPUD setCommand(byte command) {
+        this.command = command;
+        return this;
+    }
+
+    public boolean getADEC() {
+        return adec;
+    }
+
+    public SPUD setADEC(boolean adec) {
+        this.adec = adec;
+        return this;
+    }
+
+    public boolean getPDEC() {
+        return pdec;
+    }
+
+    public SPUD setPDEC(boolean pdec) {
+        this.pdec = pdec;
+        return this;
+    }
+
+    public byte getReserved() {
+        return reserved;
+    }
+
+    public SPUD setReserved(byte reserved) {
+        this.reserved = reserved;
+        return this;
+    }
+
+    @Override
+    public byte[] serialize() {
+        byte[] payloadData = null;
+        if (payload != null) {
+            payload.setParent(this);
+            payloadData = payload.serialize();
+        }
+        int length = HEADER_LENGTH + ((payloadData == null) ? 0 : payloadData.length);
+        byte[] data = new byte[length];
+        ByteBuffer bb = ByteBuffer.wrap(data);
+        bb.put(MAGIC_CONSTANT);
+        bb.putLong(tubeID);
+        byte adecBit = (byte) ((adec) ? 1 : 0);
+        byte pdecBit = (byte) ((pdec) ? 1 : 0);
+        byte lastByte = (byte) (((command & 0x3) << 6) | ((adecBit & 0x1) << 5)
+                | ((pdecBit & 0x1) << 4) | (reserved & 0xf));
+        bb.put(lastByte);
+        if (payloadData != null) {
+            bb.put(payloadData);
+        }
+        return data;
+    }
+
+    @Override
+    public IPacket deserialize(byte[] data, int offset, int length)
+            throws PacketParsingException {
+        ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+        byte[] magicConstant = new byte[MAGIC_CONSTANT.length];
+        bb.get(magicConstant, 0, MAGIC_CONSTANT.length);
+        if (!Arrays.equals(magicConstant, MAGIC_CONSTANT)) {
+            throw new PacketParsingException("Magic constant is incorrect.");
+        }
+        tubeID = bb.getLong();
+        byte lastByte = bb.get();
+        command = (byte) ((lastByte & 0xc0) >>> 6);
+        adec = ((lastByte & 0x20) != 0);
+        pdec = ((lastByte & 0x10) != 0);
+        reserved = (byte) (lastByte & 0xF);
+        // TODO: make sure reserved bits are 0 for this version.
+        this.payload = new Data();
+        this.payload = payload.deserialize(data, bb.position(), bb.limit()-bb.position());
+        this.payload.setParent(this);
+        return this;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + (adec ? 1231 : 1237);
+        result = prime * result + command;
+        result = prime * result + (pdec ? 1231 : 1237);
+        result = prime * result + reserved;
+        result = prime * result + (int) (tubeID ^ (tubeID >>> 32));
+        return result;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (!super.equals(obj))
+            return false;
+        if (!(obj instanceof SPUD))
+            return false;
+        SPUD other = (SPUD) obj;
+        if (adec != other.adec)
+            return false;
+        if (command != other.command)
+            return false;
+        if (pdec != other.pdec)
+            return false;
+        if (reserved != other.reserved)
+            return false;
+        if (tubeID != other.tubeID)
+            return false;
+        return true;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/packet/UDP.java b/src/main/java/net/floodlightcontroller/packet/UDP.java
index a5ee35f2c24971cca72c6d183bc2de2bea184f88..67302ae01aad3f2757a2ac9cade9856293c6e9cb 100644
--- a/src/main/java/net/floodlightcontroller/packet/UDP.java
+++ b/src/main/java/net/floodlightcontroller/packet/UDP.java
@@ -1,7 +1,7 @@
 /**
-*    Copyright 2011, Big Switch Networks, Inc. 
+*    Copyright 2011, Big Switch Networks, Inc.
 *    Originally created by David Erickson, Stanford 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
@@ -18,6 +18,7 @@
 package net.floodlightcontroller.packet;
 
 import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -39,7 +40,7 @@ public class UDP extends BasePacket {
          */
         UDP.decodeMap.put(DHCP_CLIENT_PORT, DHCP.class);
         UDP.decodeMap.put(DHCP_SERVER_PORT, DHCP.class);
-        
+
     }
 
     protected TransportPort sourcePort;
@@ -61,7 +62,7 @@ public class UDP extends BasePacket {
         this.sourcePort = sourcePort;
         return this;
     }
-    
+
     /**
      * @param sourcePort the sourcePort to set
      */
@@ -84,7 +85,7 @@ public class UDP extends BasePacket {
         this.destinationPort = destinationPort;
         return this;
     }
-    
+
     /**
      * @param destinationPort the destinationPort to set
      */
@@ -227,6 +228,14 @@ public class UDP extends BasePacket {
         this.destinationPort = TransportPort.of((int) (bb.getShort() & 0xffff)); // convert range 0 to 65534, not -32768 to 32767
         this.length = bb.getShort();
         this.checksum = bb.getShort();
+        // Grab a snapshot of the first four bytes of the UDP payload.
+        // We will use these to see if the payload is SPUD, without
+        // disturbing the existing byte buffer's offsets.
+        ByteBuffer bb_spud = bb.slice();
+        byte[] maybe_spud_bytes = new byte[SPUD.MAGIC_CONSTANT.length];
+        if (bb_spud.remaining() >= SPUD.MAGIC_CONSTANT.length) {
+            bb_spud.get(maybe_spud_bytes, 0, SPUD.MAGIC_CONSTANT.length);
+        }
 
         if (UDP.decodeMap.containsKey(this.destinationPort)) {
             try {
@@ -240,6 +249,9 @@ public class UDP extends BasePacket {
             } catch (Exception e) {
                 throw new RuntimeException("Failure instantiating class", e);
             }
+        } else if (Arrays.equals(maybe_spud_bytes, SPUD.MAGIC_CONSTANT)
+                && bb.remaining() >= SPUD.HEADER_LENGTH) {
+            this.payload = new SPUD();
         } else {
             this.payload = new Data();
         }
diff --git a/src/test/java/net/floodlightcontroller/packet/SPUDTest.java b/src/test/java/net/floodlightcontroller/packet/SPUDTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..82cd29e2d6e30e8d632d97869de388882e403042
--- /dev/null
+++ b/src/test/java/net/floodlightcontroller/packet/SPUDTest.java
@@ -0,0 +1,114 @@
+package net.floodlightcontroller.packet;
+
+import static org.junit.Assert.assertTrue;
+import java.util.Arrays;
+import org.junit.Test;
+
+/**
+ * @author Jacob Chappell (jacob.chappell@uky.edu)
+ */
+public class SPUDTest {
+    @Test
+    public void testSerializeCommandOpen() {
+        byte[] expected = new byte[] {
+                (byte) 0xd8, 0x00, 0x00, (byte) 0xd8,
+                (byte) 0xb6, 0x40, 0x17, (byte) 0x88,
+                0x0a, 0x51, 0x01, 0x07, 0x40
+        };
+        SPUD packet = (new SPUD())
+                .setTubeID(0xb64017880a510107L)
+                .setCommand(SPUD.COMMAND_OPEN)
+                .setADEC(false)
+                .setPDEC(false)
+                .setReserved((byte) 0);
+        byte[] actual = packet.serialize();
+        assertTrue(Arrays.equals(expected, actual));
+    }
+
+    @Test
+    public void testSerializeCommandDataEmpty() {
+        byte[] expected = new byte[] {
+                (byte) 0xd8, 0x00, 0x00, (byte) 0xd8,
+                (byte) 0xb6, 0x40, 0x17, (byte) 0x88,
+                0x0a, 0x51, 0x01, 0x07, 0x00
+        };
+        SPUD packet = (new SPUD())
+                .setTubeID(0xb64017880a510107L)
+                .setCommand(SPUD.COMMAND_DATA)
+                .setADEC(false)
+                .setPDEC(false)
+                .setReserved((byte) 0);
+        byte[] actual = packet.serialize();
+        assertTrue(Arrays.equals(expected, actual));
+    }
+
+    @Test
+    public void testSerializeCommandDataEmptyWithADEC() {
+        byte[] expected = new byte[] {
+                (byte) 0xd8, 0x00, 0x00, (byte) 0xd8,
+                (byte) 0xb6, 0x40, 0x17, (byte) 0x88,
+                0x0a, 0x51, 0x01, 0x07, 0x20
+        };
+        SPUD packet = (new SPUD())
+                .setTubeID(0xb64017880a510107L)
+                .setCommand(SPUD.COMMAND_DATA)
+                .setADEC(true)
+                .setPDEC(false)
+                .setReserved((byte) 0);
+        byte[] actual = packet.serialize();
+        assertTrue(Arrays.equals(expected, actual));
+    }
+
+    @Test
+    public void testSerializeCommandDataEmptyWithPDEC() {
+        byte[] expected = new byte[] {
+                (byte) 0xd8, 0x00, 0x00, (byte) 0xd8,
+                (byte) 0xb6, 0x40, 0x17, (byte) 0x88,
+                0x0a, 0x51, 0x01, 0x07, 0x10
+        };
+        SPUD packet = (new SPUD())
+                .setTubeID(0xb64017880a510107L)
+                .setCommand(SPUD.COMMAND_DATA)
+                .setADEC(false)
+                .setPDEC(true)
+                .setReserved((byte) 0);
+        byte[] actual = packet.serialize();
+        assertTrue(Arrays.equals(expected, actual));
+    }
+
+    @Test
+    public void testSerializeCommandDataEmptyWithBoth() {
+        byte[] expected = new byte[] {
+                (byte) 0xd8, 0x00, 0x00, (byte) 0xd8,
+                (byte) 0xb6, 0x40, 0x17, (byte) 0x88,
+                0x0a, 0x51, 0x01, 0x07, 0x30
+        };
+        SPUD packet = (new SPUD())
+                .setTubeID(0xb64017880a510107L)
+                .setCommand(SPUD.COMMAND_DATA)
+                .setADEC(true)
+                .setPDEC(true)
+                .setReserved((byte) 0);
+        byte[] actual = packet.serialize();
+        assertTrue(Arrays.equals(expected, actual));
+    }
+
+    @Test
+    public void testDeserialize() throws PacketParsingException {
+        byte[] spudPacket =  {
+                (byte) 0xd8, 0x00, 0x00, (byte) 0xd8, (byte) 0xb6,
+                0x40, 0x17, (byte) 0x88, 0x0a, 0x51, 0x01, 0x07,
+                0x00, (byte) 0xa1, 0x00, (byte) 0xa2, 0x68, 0x75,
+                0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x65,
+                0x4a, 0x61, 0x63, 0x6f, 0x62, 0x67, 0x6d, 0x65,
+                0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x68, 0x61,
+                0x73, 0x20, 0x6a, 0x6f, 0x69, 0x6e, 0x65, 0x64,
+                0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x6f, 0x6f,
+                0x6d
+        };
+        SPUD packet = new SPUD();
+        packet.deserialize(spudPacket, 0, spudPacket.length);
+        byte[] packetSerialized = packet.serialize();
+        assertTrue(Arrays.equals(spudPacket, packetSerialized));
+    }
+}
diff --git a/src/test/java/net/floodlightcontroller/packet/UDPTest.java b/src/test/java/net/floodlightcontroller/packet/UDPTest.java
index bed42a2e86dea1344e2963b2d56c1cf6585f63f1..3224c2747f0f33a13132d2cdd5b52c18f35eaa69 100644
--- a/src/test/java/net/floodlightcontroller/packet/UDPTest.java
+++ b/src/test/java/net/floodlightcontroller/packet/UDPTest.java
@@ -1,7 +1,7 @@
 /**
-*    Copyright 2011, Big Switch Networks, Inc. 
+*    Copyright 2011, Big Switch Networks, Inc.
 *    Originally created by David Erickson, Stanford 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
@@ -16,10 +16,11 @@
 **/
 
 /**
- * 
+ *
  */
 package net.floodlightcontroller.packet;
 
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import java.util.Arrays;
@@ -52,4 +53,40 @@ public class UDPTest {
         byte[] actual = packet.serialize();
         assertTrue(Arrays.equals(expected, actual));
     }
+
+    @Test
+    public void testDeserializeNotSPUD() throws PacketParsingException {
+        byte[] data = new byte[] {
+                0x04, (byte) 0x89, 0x00, 0x35, 0x00, 0x2C,
+                (byte) 0xAB, (byte) 0xB4, 0x00, 0x01, 0x01,
+                0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x04, 0x70, 0x6F, 0x70, 0x64,
+                0x02, 0x69, 0x78, 0x06, 0x6E, 0x65, 0x74,
+                0x63, 0x6F, 0x6D, 0x03, 0x63, 0x6F, 0x6D,
+                0x00, 0x00, 0x01, 0x00, 0x01
+        };
+        UDP packet = new UDP();
+        packet.deserialize(data, 0, data.length);
+        IPacket thePayload = packet.getPayload();
+        assertFalse(thePayload instanceof SPUD);
+        byte[] packetSerialized = packet.serialize();
+        assertTrue(Arrays.equals(data, packetSerialized));
+    }
+
+    @Test
+    public void testDeserializeSPUD() throws PacketParsingException {
+        byte[] data = new byte[] {
+                (byte) 0xd5, (byte) 0xdf, (byte) 0x98, 0x27,
+                0x00, 0x15, (byte) 0xfe, 0x28, (byte) 0xd8,
+                0x00, 0x00, (byte) 0xd8, (byte) 0xc2, 0x6f,
+                0x7a, 0x7d, 0x56, (byte) 0xa2, (byte) 0xe5,
+                (byte) 0xa8, 0x40
+        };
+        UDP packet = new UDP();
+        packet.deserialize(data, 0, data.length);
+        IPacket thePayload = packet.getPayload();
+        assertTrue(thePayload instanceof SPUD);
+        byte[] packetSerialized = packet.serialize();
+        assertTrue(Arrays.equals(data, packetSerialized));
+    }
 }