Skip to content
Snippets Groups Projects
Commit 470e9ba4 authored by Ryan Izard's avatar Ryan Izard
Browse files

Merge pull request #558 from phpHavok/master

IPv6 (New)
parents 6a422a10 a41e1d4c
No related branches found
No related tags found
No related merge requests found
/**
* 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
......@@ -35,6 +35,7 @@ public class Ethernet extends BasePacket {
public static final short TYPE_ARP = 0x0806;
public static final short TYPE_RARP = (short) 0x8035;
public static final short TYPE_IPv4 = 0x0800;
public static final short TYPE_IPv6 = (short) 0x86DD;
public static final short TYPE_LLDP = (short) 0x88cc;
public static final short TYPE_BSN = (short) 0x8942;
public static final short VLAN_UNTAGGED = VlanVid.ZERO.getVlan(); // untagged vlan must be 0x0000 for loxi. We can use the convenient ZERO field
......@@ -46,6 +47,7 @@ public class Ethernet extends BasePacket {
etherTypeClassMap.put(TYPE_ARP, ARP.class);
etherTypeClassMap.put(TYPE_RARP, ARP.class);
etherTypeClassMap.put(TYPE_IPv4, IPv4.class);
etherTypeClassMap.put(TYPE_IPv6, IPv6.class);
etherTypeClassMap.put(TYPE_LLDP, LLDP.class);
etherTypeClassMap.put(TYPE_BSN, BSN.class);
}
......@@ -64,7 +66,7 @@ public class Ethernet extends BasePacket {
super();
this.vlanID = VLAN_UNTAGGED;
}
/**
* @return the destination MAC
*/
......@@ -79,7 +81,7 @@ public class Ethernet extends BasePacket {
this.destinationMACAddress = MacAddress.of(destinationMACAddress);
return this;
}
/**
* @param destinationMACAddress the destination MAC to set
*/
......@@ -110,7 +112,7 @@ public class Ethernet extends BasePacket {
this.sourceMACAddress = MacAddress.of(sourceMACAddress);
return this;
}
/**
* @param sourceMACAddress the source MAC to set
*/
......@@ -171,7 +173,7 @@ public class Ethernet extends BasePacket {
this.etherType = etherType;
return this;
}
/**
* @return True if the Ethernet frame is broadcast, false otherwise
*/
......@@ -179,7 +181,7 @@ public class Ethernet extends BasePacket {
assert(destinationMACAddress.getLength() == 6);
return destinationMACAddress.isBroadcast();
}
/**
* @return True is the Ethernet frame is multicast, False otherwise
*/
......@@ -248,9 +250,9 @@ public class Ethernet extends BasePacket {
bb.get(srcAddr);
this.sourceMACAddress = MacAddress.of(srcAddr);
/*
/*
* The ethertype is represented as 2 bytes in the packet header;
* however, EthType can only parse an int. Negative shorts (1 in
* however, EthType can only parse an int. Negative shorts (1 in
* the most sig place b/c 2's complement) are still valid ethertypes,
* but it doesn't appear this way unless we treat the sign bit as
* part of an unsigned number. If we natively cast the short to an
......@@ -269,7 +271,7 @@ public class Ethernet extends BasePacket {
this.vlanID = VLAN_UNTAGGED;
}
this.etherType = etherType;
IPacket payload;
if (Ethernet.etherTypeClassMap.containsKey((short) this.etherType.getValue())) {
Class<? extends IPacket> clazz = Ethernet.etherTypeClassMap.get((short) this.etherType.getValue());
......@@ -321,7 +323,7 @@ public class Ethernet extends BasePacket {
if (macBytes.length != 6)
return false;
for (int i = 0; i < 6; ++i) {
if (HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1 ||
if (HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1 ||
HEXES.indexOf(macBytes[i].toUpperCase().charAt(1)) == -1) {
return false;
}
......@@ -333,7 +335,7 @@ public class Ethernet extends BasePacket {
* Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
* matter, and returns a corresponding byte[].
* @param macAddress The MAC address to convert into a bye array
* @return The macAddress as a byte array
* @return The macAddress as a byte array
*/
public static byte[] toMACAddress(String macAddress) {
return MacAddress.of(macAddress).getBytes();
......@@ -358,7 +360,7 @@ public class Ethernet extends BasePacket {
public static byte[] toByteArray(long macAddress) {
return MacAddress.of(macAddress).getBytes();
}
@Override
public int hashCode() {
final int prime = 31;
......@@ -410,7 +412,7 @@ public class Ethernet extends BasePacket {
return false;
return true;
}
/* (non-Javadoc)
* @see java.lang.Object#toString(java.lang.Object)
*/
......
package net.floodlightcontroller.packet;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import org.projectfloodlight.openflow.types.IPv6Address;
import org.projectfloodlight.openflow.types.IpProtocol;
/**
* @author Jacob Chappell (jacob.chappell@uky.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;
}
}
package net.floodlightcontroller.packet;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import org.junit.Test;
import org.projectfloodlight.openflow.types.IPv6Address;
import org.projectfloodlight.openflow.types.IpProtocol;
/**
* @author Jacob Chappell (jacob.chappell@uky.edu)
*/
public class IPv6Test {
@Test
public void testSerializeWithoutPayload() {
byte[] expected = new byte[] {
0x64, 0x2B, 0x16, (byte) 0x95, 0x00, 0x00,
0x11, (byte) 0xE1, (byte) 0xFE, (byte) 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7A, (byte) 0xC5, (byte) 0xFF, (byte) 0xFE,
0x2E, 0x77, 0x35, (byte) 0xFE, (byte) 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x77, 0x5D, (byte) 0xFF, (byte) 0xFE,
(byte) 0xC2, 0x30, (byte) 0xFD
};
IPv6 packet = (new IPv6())
.setTrafficClass((byte) 0x42)
.setFlowLabel(0xB1695)
.setPayloadLength((short) 0)
.setNextHeader(IpProtocol.of((short) 0x11))
.setHopLimit((byte) 0xE1)
.setSourceAddress(IPv6Address.of("fe80::7a:c5ff:fe2e:7735"))
.setDestinationAddress(IPv6Address.of("fe80::77:5dff:fec2:30fd"));
byte[] actual = packet.serialize();
assertTrue(Arrays.equals(expected, actual));
}
@Test
public void testDeserialize() throws PacketParsingException {
byte[] spudPacket = {
0x64, 0x2B, 0x16, (byte) 0x95, 0x00, 0x15,
0x11, (byte) 0xE1, (byte) 0xFE, (byte) 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7A, (byte) 0xC5, (byte) 0xFF, (byte) 0xFE,
0x2E, 0x77, 0x35, (byte) 0xFE, (byte) 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x77, 0x5D, (byte) 0xFF, (byte) 0xFE,
(byte) 0xC2, 0x30, (byte) 0xFD, (byte) 0xD2,
0x01, 0x05, 0x7A, 0x00, 0x15, (byte) 0xF6,
(byte) 0xC8, (byte) 0xD8, 0x00, 0x00,
(byte) 0xD8, 0x4A, (byte) 0xC3, (byte) 0xF2,
0x02, 0x44, 0x75, (byte) 0x97, 0x69, 0x40
};
IPv6 packet = new IPv6();
packet.deserialize(spudPacket, 0, spudPacket.length);
byte[] packetSerialized = packet.serialize();
assertTrue(Arrays.equals(spudPacket, packetSerialized));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment