diff --git a/src/main/java/net/floodlightcontroller/packet/Ethernet.java b/src/main/java/net/floodlightcontroller/packet/Ethernet.java
index d9feae28aa1b21cc1ae35ff4585b13e010eadc8e..b3ef406e69298fc785e975cb488fb3833de5d36b 100644
--- a/src/main/java/net/floodlightcontroller/packet/Ethernet.java
+++ b/src/main/java/net/floodlightcontroller/packet/Ethernet.java
@@ -476,6 +476,17 @@ public class Ethernet extends BasePacket {
             sb.append("\nnw_proto: ");
             sb.append(p.getProtocol());
         }
+        else if (pkt instanceof IPv6) {
+        	IPv6 p = (IPv6) pkt;
+        	sb.append("\nnw_src: ");
+            sb.append(p.getSourceAddress().toString());
+            sb.append("\nnw_dst: ");
+            sb.append(p.getDestinationAddress().toString());
+            sb.append("\nnw_tclass: ");
+            sb.append(p.getTrafficClass());
+            sb.append("\nnw_proto: ");
+            sb.append(p.getNextHeader().toString());
+        }
         else if (pkt instanceof DHCP) {
             sb.append("\ndhcp packet");
         }
@@ -488,9 +499,8 @@ public class Ethernet extends BasePacket {
         else if (pkt instanceof BPDU) {
             sb.append("\nbpdu packet");
         }
-        else sb.append("\nunknwon packet");
+        else sb.append("\nunknown packet");
 
         return sb.toString();
     }
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/packet/IPv6.java b/src/main/java/net/floodlightcontroller/packet/IPv6.java
index d8af941018bd2ad2f8ae0b37f02d0cee7522d29c..e15b45e024fd9a4ecdf6aa9f9e1915a457ab8e5a 100644
--- a/src/main/java/net/floodlightcontroller/packet/IPv6.java
+++ b/src/main/java/net/floodlightcontroller/packet/IPv6.java
@@ -1,255 +1,304 @@
+/**
+ *    Copyright 2015, 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
+ *
+ *         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 net.floodlightcontroller.packet;
 
 import java.nio.ByteBuffer;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 
 import org.projectfloodlight.openflow.types.IPv6Address;
 import org.projectfloodlight.openflow.types.IpProtocol;
 
 /**
  * @author Jacob Chappell (jacob.chappell@uky.edu)
+ * @edited Ryan Izard, ryan.izard@bigswitch.com, rizard@g.clemson.edu
  */
 public class IPv6 extends BasePacket {
-    public static Map<IpProtocol, Class<? extends IPacket>> nextHeaderClassMap;
-
-    static {
-        nextHeaderClassMap = new HashMap<IpProtocol, Class<? extends IPacket>>();
-        // TODO: Add ICMPv6, IPv6 Options, etc..
-        nextHeaderClassMap.put(IpProtocol.TCP, TCP.class);
-        nextHeaderClassMap.put(IpProtocol.UDP, UDP.class);
-    }
-
-    public static final int HEADER_LENGTH = 40;
-
-    protected byte version;
-    protected byte trafficClass;
-    protected int flowLabel;
-    protected short payloadLength;
-    protected IpProtocol nextHeader;
-    protected byte hopLimit;
-    protected IPv6Address sourceAddress;
-    protected IPv6Address destinationAddress;
-
-    public IPv6() {
-        super();
-        this.version = 6;
-        nextHeader = IpProtocol.NONE;
-        sourceAddress = IPv6Address.NONE;
-        destinationAddress = IPv6Address.NONE;
-    }
-
-    public byte getVersion() {
-        return version;
-    }
-
-    public IPv6 setVersion(byte version) {
-        this.version = version;
-        return this;
-    }
-
-    public byte getTrafficClass() {
-        return trafficClass;
-    }
-
-    public IPv6 setTrafficClass(byte trafficClass) {
-        this.trafficClass = trafficClass;
-        return this;
-    }
-
-    public int getFlowLabel() {
-        return flowLabel;
-    }
-
-    public IPv6 setFlowLabel(int flowLabel) {
-        this.flowLabel = flowLabel;
-        return this;
-    }
-
-    public short getPayloadLength() {
-        return payloadLength;
-    }
-
-    public IPv6 setPayloadLength(short payloadLength) {
-        this.payloadLength = payloadLength;
-        return this;
-    }
-
-    public IpProtocol getNextHeader() {
-        return nextHeader;
-    }
-
-    public IPv6 setNextHeader(IpProtocol nextHeader) {
-        this.nextHeader = nextHeader;
-        return this;
-    }
-
-    public byte getHopLimit() {
-        return hopLimit;
-    }
-
-    public IPv6 setHopLimit(byte hopLimit) {
-        this.hopLimit = hopLimit;
-        return this;
-    }
-
-    public IPv6Address getSourceAddress() {
-        return sourceAddress;
-    }
-
-    public IPv6 setSourceAddress(IPv6Address sourceAddress) {
-        this.sourceAddress = sourceAddress;
-        return this;
-    }
-
-    public IPv6Address getDestinationAddress() {
-        return destinationAddress;
-    }
-
-    public IPv6 setDestinationAddress(IPv6Address destinationAddress) {
-        this.destinationAddress = destinationAddress;
-        return this;
-    }
-
-    @Override
-    public byte[] serialize() {
-        // Get the raw bytes of the payload we encapsulate.
-        byte[] payloadData = null;
-        if (this.payload != null) {
-            this.payload.setParent(this);
-            payloadData = this.payload.serialize();
-        }
-        // Update our internal payload length.
-        this.payloadLength = (short) ((payloadData != null) ? payloadData.length : 0);
-        // Create a byte buffer to hold the IPv6 packet structure.
-        byte[] data = new byte[HEADER_LENGTH + this.payloadLength];
-        ByteBuffer bb = ByteBuffer.wrap(data);
-        // Add header fields to the byte buffer in the correct order.
-        // Fear not the bit magic that must occur.
-        bb.put((byte) (((this.version & 0xF) << 4) |
-                ((this.trafficClass & 0xF0) >>> 4)));
-        bb.put((byte) (((this.trafficClass & 0xF) << 4) |
-                ((this.flowLabel & 0xF0000) >>> 16)));
-        bb.putShort((short) (this.flowLabel & 0xFFFF));
-        bb.putShort(this.payloadLength);
-        bb.put((byte) this.nextHeader.getIpProtocolNumber());
-        bb.put(this.hopLimit);
-        bb.put(this.sourceAddress.getBytes());
-        bb.put(this.destinationAddress.getBytes());
-        // Add the payload to the byte buffer, if necessary.
-        if (payloadData != null)
-            bb.put(payloadData);
-        // We're done! Return the data.
-        return data;
-    }
-
-    @Override
-    public IPacket deserialize(byte[] data, int offset, int length)
-            throws PacketParsingException {
-        // Wrap the data in a byte buffer for easier retrieval.
-        ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
-        // Retrieve values from IPv6 header.
-        byte firstByte = bb.get();
-        byte secondByte = bb.get();
-        this.version = (byte) ((firstByte & 0xF0) >>> 4);
-        if (this.version != 6) {
-            throw new PacketParsingException(
-                    "Invalid version for IPv6 packet: " +
-                    this.version);
-        }
-        this.trafficClass = (byte) (((firstByte & 0xF) << 4) |
-                ((secondByte & 0xF0) >>> 4));
-        this.flowLabel = ((secondByte & 0xF) << 16) |
-                (bb.getShort() & 0xFFFF);
-        this.payloadLength = bb.getShort();
-        this.nextHeader = IpProtocol.of(bb.get()); // TODO: U8.f()?
-        this.hopLimit = bb.get();
-        byte[] sourceAddress = new byte[16];
-        bb.get(sourceAddress, 0, 16);
-        byte[] destinationAddress = new byte[16];
-        bb.get(destinationAddress, 0, 16);
-        this.sourceAddress = IPv6Address.of(sourceAddress);
-        this.destinationAddress = IPv6Address.of(destinationAddress);
-        // Retrieve the payload, if possible.
-        IPacket payload;
-        if (IPv6.nextHeaderClassMap.containsKey(this.nextHeader)) {
-            Class<? extends IPacket> clazz = IPv6.nextHeaderClassMap.get(this.nextHeader);
-            try {
-                payload = clazz.newInstance();
-            } catch (Exception e) {
-                throw new RuntimeException("Error parsing payload for IPv6 packet", e);
-            }
-        } else {
-            payload = new Data();
-        }
-        // Deserialize as much of the payload as we can (hopefully all of it).
-        this.payload = payload.deserialize(data, bb.position(),
-                Math.min(this.payloadLength, bb.limit() - bb.position()));
-        this.payload.setParent(this);
-        // We're done!
-        return this;
-    }
-
-    /* (non-Javadoc)
-     * @see java.lang.Object#hashCode()
-     */
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = super.hashCode();
-        result = prime
-                * result
-                + ((destinationAddress == null) ? 0 : destinationAddress
-                        .hashCode());
-        result = prime * result + flowLabel;
-        result = prime * result + hopLimit;
-        result = prime * result
-                + ((nextHeader == null) ? 0 : nextHeader.hashCode());
-        result = prime * result + payloadLength;
-        result = prime * result
-                + ((sourceAddress == null) ? 0 : sourceAddress.hashCode());
-        result = prime * result + trafficClass;
-        result = prime * result + version;
-        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 IPv6))
-            return false;
-        IPv6 other = (IPv6) obj;
-        if (destinationAddress == null) {
-            if (other.destinationAddress != null)
-                return false;
-        } else if (!destinationAddress.equals(other.destinationAddress))
-            return false;
-        if (flowLabel != other.flowLabel)
-            return false;
-        if (hopLimit != other.hopLimit)
-            return false;
-        if (nextHeader == null) {
-            if (other.nextHeader != null)
-                return false;
-        } else if (!nextHeader.equals(other.nextHeader))
-            return false;
-        if (payloadLength != other.payloadLength)
-            return false;
-        if (sourceAddress == null) {
-            if (other.sourceAddress != null)
-                return false;
-        } else if (!sourceAddress.equals(other.sourceAddress))
-            return false;
-        if (trafficClass != other.trafficClass)
-            return false;
-        if (version != other.version)
-            return false;
-        return true;
-    }
+	public static Map<IpProtocol, Class<? extends IPacket>> nextHeaderClassMap;
+
+	static {
+		nextHeaderClassMap = new HashMap<IpProtocol, Class<? extends IPacket>>();
+		// TODO: Add ICMPv6, IPv6 Options, etc..
+		nextHeaderClassMap.put(IpProtocol.TCP, TCP.class);
+		nextHeaderClassMap.put(IpProtocol.UDP, UDP.class);
+	}
+
+	public static final int HEADER_LENGTH = 40;
+
+	protected byte version;
+	protected byte trafficClass;
+	protected int flowLabel;
+	protected short payloadLength;
+	protected IpProtocol nextHeader;
+	protected byte hopLimit;
+	protected IPv6Address sourceAddress;
+	protected IPv6Address destinationAddress;
+
+	public IPv6() {
+		super();
+		this.version = 6;
+		nextHeader = IpProtocol.NONE;
+		sourceAddress = IPv6Address.NONE;
+		destinationAddress = IPv6Address.NONE;
+	}
+
+	public byte getVersion() {
+		return version;
+	}
+
+	public IPv6 setVersion(byte version) {
+		this.version = version;
+		return this;
+	}
+
+	public byte getTrafficClass() {
+		return trafficClass;
+	}
+
+	public IPv6 setTrafficClass(byte trafficClass) {
+		this.trafficClass = trafficClass;
+		return this;
+	}
+
+	public int getFlowLabel() {
+		return flowLabel;
+	}
+
+	public IPv6 setFlowLabel(int flowLabel) {
+		this.flowLabel = flowLabel;
+		return this;
+	}
+
+	public short getPayloadLength() {
+		return payloadLength;
+	}
+
+	public IPv6 setPayloadLength(short payloadLength) {
+		this.payloadLength = payloadLength;
+		return this;
+	}
+
+	public IpProtocol getNextHeader() {
+		return nextHeader;
+	}
+
+	public IPv6 setNextHeader(IpProtocol nextHeader) {
+		this.nextHeader = nextHeader;
+		return this;
+	}
+
+	public byte getHopLimit() {
+		return hopLimit;
+	}
+
+	public IPv6 setHopLimit(byte hopLimit) {
+		this.hopLimit = hopLimit;
+		return this;
+	}
+
+	public IPv6Address getSourceAddress() {
+		return sourceAddress;
+	}
+
+	public IPv6 setSourceAddress(IPv6Address sourceAddress) {
+		this.sourceAddress = sourceAddress;
+		return this;
+	}
+
+	public IPv6Address getDestinationAddress() {
+		return destinationAddress;
+	}
+
+	public IPv6 setDestinationAddress(IPv6Address destinationAddress) {
+		this.destinationAddress = destinationAddress;
+		return this;
+	}
+
+	@Override
+	public byte[] serialize() {
+		// Get the raw bytes of the payload we encapsulate.
+		byte[] payloadData = null;
+		if (this.payload != null) {
+			this.payload.setParent(this);
+			payloadData = this.payload.serialize();
+			/* 
+			 * If we forgot to include the IpProtocol before serializing, 
+			 * try to ascertain what it is from the payload. If it's not
+			 * a payload type we know about, we'll throw an exception.
+			 */
+			if ((this.nextHeader == null || this.nextHeader.equals(IpProtocol.NONE))) {
+				if (IPv6.nextHeaderClassMap.containsValue(this.payload.getClass())) {
+					Set<Map.Entry<IpProtocol, Class<? extends IPacket>>> entries = IPv6.nextHeaderClassMap.entrySet();
+					for (Map.Entry<IpProtocol, Class<? extends IPacket>> m : entries) {
+						if (m.getValue().equals(this.payload.getClass())) {            		
+							this.setNextHeader(m.getKey());
+							log.warn("Setting previously unset IPv6 'next header' to {} as detected by payload {}", m.getKey(), this.getPayload().getClass().toString());
+							break;
+						}
+					}
+				} else if (this.payload instanceof Data) {
+					/* we're good -- there shouldn't be an IpProtocol set it it's just data */
+				} else {
+					throw new IllegalArgumentException("IpProtocol is unset in IPv6 packet " + this.toString() + ". Unable to determine payload type to set for payload " + this.getPayload().getClass().toString());
+				}
+			}
+		}
+		// Update our internal payload length.
+		this.payloadLength = (short) ((payloadData != null) ? payloadData.length : 0);
+		// Create a byte buffer to hold the IPv6 packet structure.
+		byte[] data = new byte[HEADER_LENGTH + this.payloadLength];
+		ByteBuffer bb = ByteBuffer.wrap(data);
+		// Add header fields to the byte buffer in the correct order.
+		// Fear not the bit magic that must occur.
+		bb.put((byte) (((this.version & 0xF) << 4) |
+				((this.trafficClass & 0xF0) >>> 4)));
+		bb.put((byte) (((this.trafficClass & 0xF) << 4) |
+				((this.flowLabel & 0xF0000) >>> 16)));
+		bb.putShort((short) (this.flowLabel & 0xFFFF));
+		bb.putShort(this.payloadLength);
+		bb.put((byte) this.nextHeader.getIpProtocolNumber());
+		bb.put(this.hopLimit);
+		bb.put(this.sourceAddress.getBytes());
+		bb.put(this.destinationAddress.getBytes());
+		// Add the payload to the byte buffer, if necessary.
+		if (payloadData != null)
+			bb.put(payloadData);
+		// We're done! Return the data.
+		return data;
+	}
+
+	@Override
+	public String toString() {
+		return "IPv6 [version=" + version + ", trafficClass=" + trafficClass
+				+ ", flowLabel=" + flowLabel + ", payloadLength="
+				+ payloadLength + ", nextHeader=" + nextHeader + ", hopLimit="
+				+ hopLimit + ", sourceAddress=" + sourceAddress
+				+ ", destinationAddress=" + destinationAddress + ", parent="
+				+ parent + ", payload=" + payload + "]";
+	}
+
+	@Override
+	public IPacket deserialize(byte[] data, int offset, int length)
+			throws PacketParsingException {
+		// Wrap the data in a byte buffer for easier retrieval.
+		ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+		// Retrieve values from IPv6 header.
+		byte firstByte = bb.get();
+		byte secondByte = bb.get();
+		this.version = (byte) ((firstByte & 0xF0) >>> 4);
+		if (this.version != 6) {
+			throw new PacketParsingException(
+					"Invalid version for IPv6 packet: " +
+							this.version);
+		}
+		this.trafficClass = (byte) (((firstByte & 0xF) << 4) |
+				((secondByte & 0xF0) >>> 4));
+		this.flowLabel = ((secondByte & 0xF) << 16) |
+				(bb.getShort() & 0xFFFF);
+		this.payloadLength = bb.getShort();
+		this.nextHeader = IpProtocol.of(bb.get());
+		this.hopLimit = bb.get();
+		byte[] sourceAddress = new byte[16];
+		bb.get(sourceAddress, 0, 16);
+		byte[] destinationAddress = new byte[16];
+		bb.get(destinationAddress, 0, 16);
+		this.sourceAddress = IPv6Address.of(sourceAddress);
+		this.destinationAddress = IPv6Address.of(destinationAddress);
+		// Retrieve the payload, if possible.
+		IPacket payload;
+		if (IPv6.nextHeaderClassMap.containsKey(this.nextHeader)) {
+			Class<? extends IPacket> clazz = IPv6.nextHeaderClassMap.get(this.nextHeader);
+			try {
+				payload = clazz.newInstance();
+			} catch (Exception e) {
+				throw new RuntimeException("Error parsing payload for IPv6 packet", e);
+			}
+		} else {
+			payload = new Data();
+		}
+		// Deserialize as much of the payload as we can (hopefully all of it).
+		this.payload = payload.deserialize(data, bb.position(),
+				Math.min(this.payloadLength, bb.limit() - bb.position()));
+		this.payload.setParent(this);
+		// We're done!
+		return this;
+	}
+
+	/* (non-Javadoc)
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = super.hashCode();
+		result = prime
+				* result
+				+ ((destinationAddress == null) ? 0 : destinationAddress
+						.hashCode());
+		result = prime * result + flowLabel;
+		result = prime * result + hopLimit;
+		result = prime * result
+				+ ((nextHeader == null) ? 0 : nextHeader.hashCode());
+		result = prime * result + payloadLength;
+		result = prime * result
+				+ ((sourceAddress == null) ? 0 : sourceAddress.hashCode());
+		result = prime * result + trafficClass;
+		result = prime * result + version;
+		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 IPv6))
+			return false;
+		IPv6 other = (IPv6) obj;
+		if (destinationAddress == null) {
+			if (other.destinationAddress != null)
+				return false;
+		} else if (!destinationAddress.equals(other.destinationAddress))
+			return false;
+		if (flowLabel != other.flowLabel)
+			return false;
+		if (hopLimit != other.hopLimit)
+			return false;
+		if (nextHeader == null) {
+			if (other.nextHeader != null)
+				return false;
+		} else if (!nextHeader.equals(other.nextHeader))
+			return false;
+		if (payloadLength != other.payloadLength)
+			return false;
+		if (sourceAddress == null) {
+			if (other.sourceAddress != null)
+				return false;
+		} else if (!sourceAddress.equals(other.sourceAddress))
+			return false;
+		if (trafficClass != other.trafficClass)
+			return false;
+		if (version != other.version)
+			return false;
+		return true;
+	}
 }
diff --git a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
index 748516618cc16b45ed2feddfe99642668ca6a7b7..0bb86f00d0031948b33f5ef21382f50d09694aa3 100644
--- a/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
+++ b/src/test/java/net/floodlightcontroller/devicemanager/internal/DeviceManagerImplTest.java
@@ -461,7 +461,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		assertNotSame(d1.getDeviceKey(), d2.getDeviceKey());
 		assertEquals(MockEntityClassifier.testEC, d2.getEntityClass());
 		assertArrayEquals(new VlanVid[] { VlanVid.ZERO }, d2.getVlanId());
-		assertArrayEquals(new Integer[] { }, d2.getIPv4Addresses());
+		assertArrayEquals(new IPv4Address[] { }, d2.getIPv4Addresses());
 
 		assertEquals(2, deviceManager.getAllDevices().size());
 		verify(mockListener);
@@ -2517,7 +2517,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 
 		Entity e1 = new Entity(MacAddress.of(1L), VlanVid.ofVlan(1), IPv4Address.NONE, IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, new Date(2000));
 		Device d1 = deviceManager.learnDeviceByEntity(e1);
-		assertArrayEquals(new Integer[0], d1.getIPv4Addresses());
+		assertArrayEquals(new IPv4Address[0], d1.getIPv4Addresses());
 
 
 		Entity e2 = new Entity(MacAddress.of(2L), VlanVid.ofVlan(2), IPv4Address.of(2), IPv6Address.NONE, DatapathId.NONE, OFPort.ZERO, new Date(2000));
@@ -3252,7 +3252,7 @@ public class DeviceManagerImplTest extends FloodlightTestCase {
 		// Query for Device2. Make sure we only have the more recent AP
 		// Query for the Device1. Make sure we have the two IPs we stored.
 		d = getSingleDeviceFromDeviceManager(2L);
-		assertArrayEquals(new Integer[0], d.getIPv4Addresses());
+		assertArrayEquals(new IPv4Address[0], d.getIPv4Addresses());
 		assertArrayEquals(new VlanVid[] { VlanVid.ZERO }, d.getVlanId());
 		swp = new SwitchPort(DatapathId.of(4L), OFPort.of(5));
 		assertArrayEquals(new SwitchPort[] { swp }, d.getAttachmentPoints());
diff --git a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
index 595a69d20eb968d5358b83bf48b0ef9851c1c08c..51f1faefb541b21acefbe0151385aa1a7277ad9f 100644
--- a/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
+++ b/src/test/java/net/floodlightcontroller/forwarding/ForwardingTest.java
@@ -45,6 +45,7 @@ import net.floodlightcontroller.packet.Data;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPacket;
 import net.floodlightcontroller.packet.IPv4;
+import net.floodlightcontroller.packet.IPv6;
 import net.floodlightcontroller.packet.UDP;
 import net.floodlightcontroller.routing.IRoutingService;
 import net.floodlightcontroller.routing.Route;
@@ -96,12 +97,17 @@ public class ForwardingTest extends FloodlightTestCase {
 	protected MockThreadPoolService threadPool;
 	protected IOFSwitch sw1, sw2;
 	protected OFFeaturesReply swFeatures;
-	protected IDevice srcDevice, dstDevice1, dstDevice2;
+	protected IDevice srcDevice, dstDevice1, dstDevice2; /* reuse for IPv4 and IPv6 */
 	protected OFPacketIn packetIn;
+	protected OFPacketIn packetInIPv6;
 	protected OFPacketOut packetOut;
+	protected OFPacketOut packetOutIPv6;
 	protected OFPacketOut packetOutFlooded;
+	protected OFPacketOut packetOutFloodedIPv6;
 	protected IPacket testPacket;
+	protected IPacket testPacketIPv6;
 	protected byte[] testPacketSerialized;
+	protected byte[] testPacketSerializedIPv6;
 	protected int expected_wildcards;
 	protected Date currentDate;
 	private MockSyncService mockSyncService;
@@ -115,25 +121,6 @@ public class ForwardingTest extends FloodlightTestCase {
 		cntx = new FloodlightContext();
 
 		// Module loader setup
-		/*
-        Collection<Class<? extends IFloodlightModule>> mods = new ArrayList<Class<? extends IFloodlightModule>>();
-        Collection<IFloodlightService> mockedServices = new ArrayList<IFloodlightService>();
-        mods.add(Forwarding.class);
-        routingEngine = createMock(IRoutingService.class);
-        topology = createMock(ITopologyService.class);
-        mockedServices.add(routingEngine);
-        mockedServices.add(topology);
-        FloodlightTestModuleLoader fml = new FloodlightTestModuleLoader();
-        fml.setupModules(mods, mockedServices);
-        mockFloodlightProvider =
-        		(MockFloodlightProvider) fml.getModuleByName(MockFloodlightProvider.class);
-        deviceManager =
-        		(MockDeviceManager) fml.getModuleByName(MockDeviceManager.class);
-        threadPool =
-        		(MockThreadPoolService) fml.getModuleByName(MockThreadPoolService.class);
-        forwarding =
-        		(Forwarding) fml.getModuleByName(Forwarding.class);
-		 */
 		mockFloodlightProvider = getMockFloodlightProvider();
 		forwarding = new Forwarding();
 		threadPool = new MockThreadPoolService();
@@ -143,7 +130,6 @@ public class ForwardingTest extends FloodlightTestCase {
 		mockSyncService = new MockSyncService();
 		DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier();
 
-
 		FloodlightModuleContext fmc = new FloodlightModuleContext();
 		fmc.addService(IFloodlightProviderService.class,
 				mockFloodlightProvider);
@@ -211,12 +197,27 @@ public class ForwardingTest extends FloodlightTestCase {
 				.setDestinationPort((short) 5001)
 				.setPayload(new Data(new byte[] {0x01}))));
 
-
+		testPacketIPv6 = new Ethernet()
+		.setDestinationMACAddress("00:11:22:33:44:55")
+		.setSourceMACAddress("00:44:33:22:11:00")
+		.setEtherType(EthType.IPv6)
+		.setPayload(
+				new IPv6()
+				.setHopLimit((byte) 128)
+				.setSourceAddress(IPv6Address.of(1, 1))
+				.setDestinationAddress(IPv6Address.of(2, 2))
+				.setNextHeader(IpProtocol.UDP)
+				.setPayload(new UDP()
+				.setSourcePort((short) 5000)
+				.setDestinationPort((short) 5001)
+				.setPayload(new Data(new byte[] {0x01}))));
 
 		currentDate = new Date();
 
 		// Mock Packet-in
 		testPacketSerialized = testPacket.serialize();
+		testPacketSerializedIPv6 = testPacketIPv6.serialize();
+		
 		packetIn = factory.buildPacketIn()
 				.setMatch(factory.buildMatch()
 						.setExact(MatchField.IN_PORT, OFPort.of(1))
@@ -232,6 +233,22 @@ public class ForwardingTest extends FloodlightTestCase {
 						.setBufferId(OFBufferId.NO_BUFFER)
 						.setData(testPacketSerialized)
 						.setReason(OFPacketInReason.NO_MATCH)
+						.build();		
+		packetInIPv6 = factory.buildPacketIn()
+				.setMatch(factory.buildMatch()
+						.setExact(MatchField.IN_PORT, OFPort.of(1))
+						.setExact(MatchField.ETH_SRC, MacAddress.of("00:44:33:22:11:00"))
+						.setExact(MatchField.ETH_DST, MacAddress.of("00:11:22:33:44:55"))
+						.setExact(MatchField.ETH_TYPE, EthType.IPv6)
+						.setExact(MatchField.IPV6_SRC, IPv6Address.of(1, 1))
+						.setExact(MatchField.IPV6_DST, IPv6Address.of(2, 2))
+						.setExact(MatchField.IP_PROTO, IpProtocol.UDP)
+						.setExact(MatchField.UDP_SRC, TransportPort.of(5000))
+						.setExact(MatchField.UDP_DST, TransportPort.of(5001))
+						.build())
+						.setBufferId(OFBufferId.NO_BUFFER)
+						.setData(testPacketSerializedIPv6)
+						.setReason(OFPacketInReason.NO_MATCH)
 						.build();
 
 		// Mock Packet-out
@@ -244,6 +261,13 @@ public class ForwardingTest extends FloodlightTestCase {
 				.setData(testPacketSerialized)
 				.setXid(15)
 				.build();
+		packetOutIPv6 = factory.buildPacketOut()
+				.setBufferId(this.packetInIPv6.getBufferId())
+				.setActions(poactions)
+				.setInPort(OFPort.of(1))
+				.setData(testPacketSerializedIPv6)
+				.setXid(15)
+				.build();
 
 		// Mock Packet-out with OFPP_FLOOD action
 		poactions = new ArrayList<OFAction>();
@@ -255,11 +279,25 @@ public class ForwardingTest extends FloodlightTestCase {
 				.setActions(poactions)
 				.setData(testPacketSerialized)
 				.build();
-
+		packetOutFloodedIPv6 = factory.buildPacketOut()
+				.setBufferId(this.packetInIPv6.getBufferId())
+				.setInPort(packetInIPv6.getMatch().get(MatchField.IN_PORT))
+				.setXid(17)
+				.setActions(poactions)
+				.setData(testPacketSerializedIPv6)
+				.build();
+	}
+	
+	void removeDeviceFromContext() {
 		IFloodlightProviderService.bcStore.
-		put(cntx,
-				IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
-				(Ethernet)testPacket);
+		remove(cntx,
+				IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+		IFloodlightProviderService.bcStore.
+		remove(cntx,
+				IDeviceService.CONTEXT_SRC_DEVICE);
+		IFloodlightProviderService.bcStore.
+		remove(cntx,
+				IDeviceService.CONTEXT_DST_DEVICE);
 	}
 
 	enum DestDeviceToLearn { NONE, DEVICE1 ,DEVICE2 };
@@ -313,6 +351,68 @@ public class ForwardingTest extends FloodlightTestCase {
 					dstDevice2);
 		}
 		verify(topology);
+		
+		IFloodlightProviderService.bcStore.
+		put(cntx,
+				IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
+				(Ethernet)testPacket);
+	}
+	
+	public void learnDevicesIPv6(DestDeviceToLearn destDeviceToLearn) {
+		// Build src and dest devices
+		MacAddress dataLayerSource = ((Ethernet)testPacketIPv6).getSourceMACAddress();
+		MacAddress dataLayerDest =
+				((Ethernet)testPacketIPv6).getDestinationMACAddress();
+		IPv6Address networkSource =
+				((IPv6)((Ethernet)testPacketIPv6).getPayload()).
+				getSourceAddress();
+		IPv6Address networkDest =
+				((IPv6)((Ethernet)testPacketIPv6).getPayload()).
+				getDestinationAddress();
+
+		reset(topology);
+		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1)))
+		.andReturn(true)
+		.anyTimes();
+		expect(topology.isAttachmentPointPort(DatapathId.of(2L), OFPort.of(3)))
+		.andReturn(true)
+		.anyTimes();
+		expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3)))
+		.andReturn(true)
+		.anyTimes();
+		replay(topology);
+
+		srcDevice =
+				deviceManager.learnEntity(dataLayerSource, VlanVid.ZERO, 
+						IPv4Address.NONE, networkSource,
+						DatapathId.of(1), OFPort.of(1));
+		IDeviceService.fcStore.put(cntx,
+				IDeviceService.CONTEXT_SRC_DEVICE,
+				srcDevice);
+		if (destDeviceToLearn == DestDeviceToLearn.DEVICE1) {
+			dstDevice1 =
+					deviceManager.learnEntity(dataLayerDest, VlanVid.ZERO, 
+							IPv4Address.NONE, networkDest,
+							DatapathId.of(2), OFPort.of(3));
+			IDeviceService.fcStore.put(cntx,
+					IDeviceService.CONTEXT_DST_DEVICE,
+					dstDevice1);
+		}
+		if (destDeviceToLearn == DestDeviceToLearn.DEVICE2) {
+			dstDevice2 =
+					deviceManager.learnEntity(dataLayerDest, VlanVid.ZERO, 
+							 IPv4Address.NONE, networkDest,
+							DatapathId.of(1), OFPort.of(3));
+			IDeviceService.fcStore.put(cntx,
+					IDeviceService.CONTEXT_DST_DEVICE,
+					dstDevice2);
+		}
+		verify(topology);
+		
+		IFloodlightProviderService.bcStore.
+		put(cntx,
+				IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
+				(Ethernet)testPacketIPv6);
 	}
 
 	@Test
@@ -381,6 +481,78 @@ public class ForwardingTest extends FloodlightTestCase {
 		OFMessage m = wc2.getValue();
 		assert (m instanceof OFFlowMod);
 		assertTrue(OFMessageUtils.equalsIgnoreXid(m, fm2));
+		
+		removeDeviceFromContext();
+	}
+	
+	@Test
+	public void testForwardMultiSwitchPathIPv6() throws Exception {
+		learnDevicesIPv6(DestDeviceToLearn.DEVICE1);
+
+		Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL);
+		Capture<OFMessage> wc2 = new Capture<OFMessage>(CaptureType.ALL);
+
+		Route route = new Route(DatapathId.of(1L), DatapathId.of(2L));
+		List<NodePortTuple> nptList = new ArrayList<NodePortTuple>();
+		nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
+		nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
+		nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(1)));
+		nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(3)));
+		route.setPath(nptList);
+		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce();
+
+		// Expected Flow-mods
+		Match match = packetInIPv6.getMatch();
+		OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
+		List<OFAction> actions = new ArrayList<OFAction>();
+		actions.add(action);
+
+		OFFlowMod fm1 = factory.buildFlowAdd()
+				.setIdleTimeout((short)5)
+				.setMatch(match)
+				.setActions(actions)
+				.setOutPort(action.getPort())
+				.setBufferId(OFBufferId.NO_BUFFER)
+				.setCookie(U64.of(2L << 52))
+				.setPriority(1)
+				.build();
+		OFFlowMod fm2 = fm1.createBuilder().build();
+
+		sw1.write(capture(wc1));
+		expectLastCall().anyTimes();
+		sw2.write(capture(wc2));
+		expectLastCall().anyTimes();
+
+		reset(topology);
+		expect(topology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.getL2DomainId(DatapathId.of(2L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.isAttachmentPointPort(DatapathId.of(1L),  OFPort.of(1))).andReturn(true).anyTimes();
+		expect(topology.isAttachmentPointPort(DatapathId.of(2L),  OFPort.of(3))).andReturn(true).anyTimes();
+		expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
+
+		// Reset mocks, trigger the packet in, and validate results
+		replay(sw1, sw2, routingEngine, topology);
+		forwarding.receive(sw1, this.packetInIPv6, cntx);
+		verify(sw1, sw2, routingEngine);
+
+		assertTrue(wc1.hasCaptured());  // wc1 should get packetout + flowmod.
+		assertTrue(wc2.hasCaptured());  // wc2 should be a flowmod.
+
+		List<OFMessage> msglist = wc1.getValues();
+
+		for (OFMessage m: msglist) {
+			if (m instanceof OFFlowMod)
+				assertTrue(OFMessageUtils.equalsIgnoreXid(fm1, m));
+			else if (m instanceof OFPacketOut) {
+				assertTrue(OFMessageUtils.equalsIgnoreXid(packetOutIPv6, m));
+			}
+		}
+
+		OFMessage m = wc2.getValue();
+		assert (m instanceof OFFlowMod);
+		assertTrue(OFMessageUtils.equalsIgnoreXid(m, fm2));
+		
+		removeDeviceFromContext();
 	}
 
 	@Test
@@ -433,9 +605,66 @@ public class ForwardingTest extends FloodlightTestCase {
 
 		assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), fm1));
 		assertTrue(OFMessageUtils.equalsIgnoreXid(wc2.getValue(), packetOut));
+		
+		removeDeviceFromContext();
+	}
+	
+	@Test
+	public void testForwardSingleSwitchPathIPv6() throws Exception {
+		learnDevicesIPv6(DestDeviceToLearn.DEVICE2);
+
+		Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL);
+		Capture<OFMessage> wc2 = new Capture<OFMessage>(CaptureType.ALL);
+
+		Route route = new  Route(DatapathId.of(1L), DatapathId.of(1L));
+		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
+		route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
+		expect(routingEngine.getRoute(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3), U64.ZERO)).andReturn(route).atLeastOnce();
+
+		// Expected Flow-mods
+		Match match = packetInIPv6.getMatch();
+		OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
+		List<OFAction> actions = new ArrayList<OFAction>();
+		actions.add(action);
+
+		OFFlowMod fm1 = factory.buildFlowAdd()
+				.setIdleTimeout((short)5)
+				.setMatch(match)
+				.setActions(actions)
+				.setOutPort(OFPort.of(3))
+				.setBufferId(OFBufferId.NO_BUFFER)
+				.setCookie(U64.of(2L<< 52))
+				.setPriority(1)
+				.build();
+
+		// Record expected packet-outs/flow-mods
+		sw1.write(capture(wc1));
+		expectLastCall().once();
+		sw1.write(capture(wc2));
+		expectLastCall().once();
+
+		reset(topology);
+		expect(topology.isIncomingBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
+		expect(topology.getL2DomainId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
+		expect(topology.isAttachmentPointPort(DatapathId.of(1L),  OFPort.of(1))).andReturn(true).anyTimes();
+		expect(topology.isAttachmentPointPort(DatapathId.of(1L),  OFPort.of(3))).andReturn(true).anyTimes();
+
+		// Reset mocks, trigger the packet in, and validate results
+		replay(sw1, sw2, routingEngine, topology);
+		forwarding.receive(sw1, this.packetInIPv6, cntx);
+		verify(sw1, sw2, routingEngine);
+
+		assertTrue(wc1.hasCaptured());
+		assertTrue(wc2.hasCaptured());
+
+		assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), fm1));
+		assertTrue(OFMessageUtils.equalsIgnoreXid(wc2.getValue(), packetOutIPv6));
+		
+		removeDeviceFromContext();
 	}
 
 	/*TODO OFMessageDamper broken due to XID variability in OFMessages... need to fix @Test */
+	/*TODO make an IPv6 test for this once OFMessageDamper fixed */
 	public void testFlowModDampening() throws Exception {
 		learnDevices(DestDeviceToLearn.DEVICE2);
 
@@ -488,6 +717,8 @@ public class ForwardingTest extends FloodlightTestCase {
 		forwarding.receive(sw1, this.packetIn, cntx);
 		forwarding.receive(sw1, this.packetIn, cntx);
 		verify(sw1, routingEngine);
+		
+		removeDeviceFromContext();
 	}
 
 	@Test
@@ -517,6 +748,38 @@ public class ForwardingTest extends FloodlightTestCase {
 
 		assertTrue(wc1.hasCaptured());
 		assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), packetOutFlooded));
+		
+		removeDeviceFromContext();
 	}
 
-}
+	@Test
+	public void testForwardNoPathIPv6() throws Exception {
+		learnDevicesIPv6(DestDeviceToLearn.NONE);
+
+		// Set no destination attachment point or route
+		// expect no Flow-mod but expect the packet to be flooded
+
+		Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL);
+
+		// Reset mocks, trigger the packet in, and validate results
+		reset(topology);
+		expect(topology.isIncomingBroadcastAllowed(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
+		expect(topology.isAttachmentPointPort(DatapathId.of(anyLong()),
+				OFPort.of(anyShort())))
+				.andReturn(true)
+				.anyTimes();
+		expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD))
+		.andReturn(true).anyTimes();
+		// Reset XID to expected (dependent on prior unit tests)
+		sw1.write(capture(wc1));
+		expectLastCall().once();
+		replay(sw1, sw2, routingEngine, topology);
+		forwarding.receive(sw1, this.packetInIPv6, cntx);
+		verify(sw1, sw2, routingEngine);
+
+		assertTrue(wc1.hasCaptured());
+		assertTrue(OFMessageUtils.equalsIgnoreXid(wc1.getValue(), packetOutFloodedIPv6));
+		
+		removeDeviceFromContext();
+	}
+}
\ No newline at end of file