Skip to content
Snippets Groups Projects
Commit 2204df45 authored by Jacob Chappell's avatar Jacob Chappell
Browse files

Add "essentials" for IPv6 packet structure. Modify Ethernet packet to deserialize IPv6 packets.

parent b323a951
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 (payload != null) {
payload.setParent(this);
payloadData = 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[8];
bb.get(sourceAddress, 0, 8);
byte[] destinationAddress = new byte[8];
bb.get(destinationAddress, 0, 8);
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() {
// TODO: Change prime and the order of results?
final int prime = 2521;
int result = super.hashCode();
result = prime * result + this.destinationAddress.getBytes().hashCode();
result = prime * result + this.payloadLength;
result = prime * result + this.hopLimit;
result = prime * result + this.nextHeader.hashCode();
result = prime * result + this.sourceAddress.getBytes().hashCode();
result = prime * result + this.trafficClass;
result = prime * result + this.flowLabel;
result = prime * result + this.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 (!this.destinationAddress.equals(other.destinationAddress))
return false;
if (this.payloadLength != other.payloadLength)
return false;
if (this.hopLimit != other.hopLimit)
return false;
if (!this.nextHeader.equals(other.nextHeader))
return false;
if (!this.sourceAddress.equals(other.sourceAddress))
return false;
if (this.trafficClass != other.trafficClass)
return false;
if (this.flowLabel != other.flowLabel)
return false;
if (this.version != other.version)
return false;
return true;
}
}
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