import java.util.LinkedHashMap;
import java.util.Map;
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.opendaylight.controller.sal.utils.EtherTypes;
/**
* Class that represents the Ethernet frame objects
- *
- *
*/
public class Ethernet extends Packet {
private static final String DMAC = "DestinationMACAddress";
put(ETHT, new ImmutablePair<Integer, Integer>(96, 16));
}
};
- private Map<String, byte[]> fieldValues;
+ private final Map<String, byte[]> fieldValues;
/**
* Default constructor that creates and sets the HashMap
return this;
}
- @Override
- public int hashCode() {
- return HashCodeBuilder.reflectionHashCode(this);
- }
-
- @Override
- public boolean equals(Object obj) {
- return EqualsBuilder.reflectionEquals(this, obj);
- }
-
}
import java.util.LinkedHashMap;
import java.util.Map;
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
+import org.opendaylight.controller.sal.utils.NetUtils;
/**
* Class that represents the ICMP packet objects
- *
- *
*/
public class ICMP extends Packet {
- private static final String TYPECODE = "TypeCode";
+ private static final String TYPE = "Type";
private static final String CODE = "Code";
- private static final String HEADERCHECKSUM = "HeaderChecksum";
+ private static final String CHECKSUM = "Checksum";
private static final String IDENTIFIER = "Identifier";
private static final String SEQNUMBER = "SequenceNumber";
private static Map<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
private static final long serialVersionUID = 1L;
-
{
- put(TYPECODE, new ImmutablePair<Integer, Integer>(0, 8));
+ put(TYPE, new ImmutablePair<Integer, Integer>(0, 8));
put(CODE, new ImmutablePair<Integer, Integer>(8, 8));
- put(HEADERCHECKSUM, new ImmutablePair<Integer, Integer>(16, 16));
+ put(CHECKSUM, new ImmutablePair<Integer, Integer>(16, 16));
put(IDENTIFIER, new ImmutablePair<Integer, Integer>(32, 16));
put(SEQNUMBER, new ImmutablePair<Integer, Integer>(48, 16));
-
}
};
hdrFieldsMap = fieldValues;
}
- private Map<String, byte[]> fieldValues;
+ private final Map<String, byte[]> fieldValues;
@Override
public void setHeaderField(String headerField, byte[] readValue) {
}
/**
- * Sets the TypeCode of ICMP for the current ICMP object instance
- * @param short - typeCode
- * @return ICMP
+ * Sets the type for the current ICMP message
+ *
+ * @param type
+ * The ICMP message type
+ * @return This ICMP object
+ */
+ public ICMP setType(byte type) {
+ byte[] icmpType = BitBufferHelper.toByteArray(type);
+ fieldValues.put(TYPE, icmpType);
+ return this;
+ }
+
+ /**
+ * Sets the ICMP code (type subtype) for the current ICMP object instance
+ *
+ * @param code
+ * The ICMP message type subtype
+ * @return This ICMP object
*/
- public ICMP setTypeCode(short typeCode) {
- byte[] icmpTypeCode = BitBufferHelper.toByteArray(typeCode);
- fieldValues.put(TYPECODE, icmpTypeCode);
+ public ICMP setCode(byte code) {
+ byte[] icmpCode = BitBufferHelper.toByteArray(code);
+ fieldValues.put(CODE, icmpCode);
return this;
}
*/
public ICMP setChecksum(short checksum) {
byte[] icmpChecksum = BitBufferHelper.toByteArray(checksum);
- fieldValues.put(HEADERCHECKSUM, icmpChecksum);
+ fieldValues.put(CHECKSUM, icmpChecksum);
return this;
}
return this;
}
+ /**
+ * Gets the header size in bits
+ * @return The ICMP header size in bits
+ */
@Override
- public int hashCode() {
- return HashCodeBuilder.reflectionHashCode(this);
+ public int getHeaderSize() {
+ return 64;
+ }
+
+ /**
+ * Computes the ICMP checksum on the serialized ICMP message
+ *
+ * @param serialized
+ * The data stream
+ * @param start
+ * The byte index on the data stream from which the ICMP packet
+ * starts
+ * @return The checksum
+ */
+ short computeChecksum(byte[] data, int start) {
+ int sum = 0, carry = 0, finalSum = 0;
+ int end = start + this.getHeaderSize() / NetUtils.NumBitsInAByte
+ + rawPayload.length;
+ int checksumStartByte = start + getfieldOffset(CHECKSUM)
+ / NetUtils.NumBitsInAByte;
+
+ for (int i = start; i <= (end - 1); i = i + 2) {
+ // Skip, if the current bytes are checkSum bytes
+ if (i == checksumStartByte) {
+ continue;
+ }
+ StringBuffer sbuffer = new StringBuffer();
+ sbuffer.append(String.format("%02X", data[i]));
+ if (i < (data.length - 1)) {
+ sbuffer.append(String.format("%02X", data[i + 1]));
+ }
+ sum += Integer.valueOf(sbuffer.toString(), 16);
+ }
+ carry = (sum >> 16) & 0xFF;
+ finalSum = (sum & 0xFFFF) + carry;
+ return (short) ~((short) finalSum & 0xFFFF);
+ }
+
+ @Override
+ protected void postSerializeCustomOperation(byte[] serializedBytes)
+ throws PacketException {
+ byte[] checkSum = BitBufferHelper
+ .toByteArray(computeChecksum(serializedBytes, 0));
+ try {
+ BitBufferHelper.setBytes(serializedBytes, checkSum,
+ getfieldOffset(CHECKSUM), getfieldnumBits(CHECKSUM));
+ } catch (BufferException e) {
+ throw new PacketException(e.getMessage());
+ }
}
@Override
- public boolean equals(Object obj) {
- return EqualsBuilder.reflectionEquals(this, obj);
+ protected void postDeserializeCustomOperation(byte[] data, int endBitOffset) {
+ short computedChecksum = computeChecksum(data, endBitOffset / NetUtils.NumBitsInAByte);
+ short actualChecksum = BitBufferHelper.getShort(fieldValues.get(CHECKSUM));
+
+ if (computedChecksum != actualChecksum) {
+ corrupted = true;
+ }
+ }
+
+ /**
+ * Gets the checksum value stored
+ * @return the checksum
+ */
+ public short getChecksum() {
+ return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM)));
}
}
import java.util.Map;
import java.util.Random;
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.opendaylight.controller.sal.utils.IPProtocols;
/**
* Class that represents the IPv4 packet objects
- *
- *
*/
public class IPv4 extends Packet {
protected static final Logger logger = LoggerFactory
- .getLogger(IPv4.class);
+ .getLogger(IPv4.class);
private static final String VERSION = "Version";
private static final String HEADERLENGTH = "HeaderLength";
private static final String DIFFSERV = "DiffServ";
}
};
- private Map<String, byte[]> fieldValues;
+ private final Map<String, byte[]> fieldValues;
+
/**
* Default constructor that sets the version to 4, headerLength to 5,
fieldValues = new HashMap<String, byte[]>();
hdrFieldCoordMap = fieldCoordinates;
hdrFieldsMap = fieldValues;
+ corrupted = false;
setVersion((byte) 4);
setHeaderLength((byte) 5);
setDiffServ((byte) 0);
+ setECN((byte) 0);
setIdentification(generateId());
setFlags((byte) 2);
setFragmentOffset((short) 0);
- setECN((byte) 0);
}
/**
fieldValues = new HashMap<String, byte[]>();
hdrFieldCoordMap = fieldCoordinates;
hdrFieldsMap = fieldValues;
+ corrupted = false;
setVersion((byte) 4);
setHeaderLength((byte) 5);
setDiffServ((byte) 0);
+ setECN((byte) 0);
setIdentification(generateId());
setFlags((byte) 2);
setFragmentOffset((short) 0);
- setECN((byte) 0);
}
/**
}
/**
- * Gets the header length in bits, from the header length stored and options if any
- * @return HeaderLength to serialize code
+ * Gets the header size in bits
+ * @return The number of bits constituting the header
*/
@Override
public int getHeaderSize() {
int headerLen = this.getHeaderLen();
- if (headerLen == 0)
+ if (headerLen == 0) {
headerLen = 20;
+ }
byte[] options = hdrFieldsMap.get(OPTIONS);
- if (options != null)
+ if (options != null) {
headerLen += options.length;
+ }
return headerLen * NetUtils.NumBitsInAByte;
-
}
/**
}
/**
- * Computes the header checksum
- * @param byte[] hdrBytes - serialized bytes
- * @param int endBitOffset - end bit Offset
- * @return short - the computed checksum
+ * Computes the IPv4 header checksum on the passed stream of bytes
+ * representing the packet
+ *
+ * @param data
+ * The byte stream
+ * @param offset
+ * The byte offset from where the IPv4 packet starts
+ * @return The computed checksum
*/
- private short computeChecksum(byte[] hdrBytes, int endByteOffset) {
- int startByteOffset = endByteOffset - getHeaderLen();
+ short computeChecksum(byte[] data, int start) {
+ int end = start + getHeaderLen();
short checkSum = (short) 0;
int sum = 0, carry = 0, finalSum = 0;
int parsedHex = 0;
- int checksumStartByte = startByteOffset + getfieldOffset(CHECKSUM)
- / NetUtils.NumBitsInAByte;
+ int checksumStart = start
+ + (getfieldOffset(CHECKSUM) / NetUtils.NumBitsInAByte);
- for (int i = startByteOffset; i <= (endByteOffset - 1); i = i + 2) {
- //Skip, if the current bytes are checkSum bytes
- if (i == checksumStartByte)
+ for (int i = start; i <= (end - 1); i = i + 2) {
+ // Skip, if the current bytes are checkSum bytes
+ if (i == checksumStart) {
continue;
+ }
StringBuffer sbuffer = new StringBuffer();
- sbuffer.append(String.format("%02X", hdrBytes[i]));
- if (i < (hdrBytes.length - 1))
- sbuffer.append(String.format("%02X", hdrBytes[i + 1]));
+ sbuffer.append(String.format("%02X", data[i]));
+ if (i < (data.length - 1)) {
+ sbuffer.append(String.format("%02X", data[i + 1]));
+ }
parsedHex = Integer.valueOf(sbuffer.toString(), 16);
sum += parsedHex;
carry = (sum >> 16) & 0xFF;
finalSum = (sum & 0xFFFF) + carry;
checkSum = (short) ~((short) finalSum & 0xFFFF);
- return checkSum;
- }
-
- @Override
- public int hashCode() {
- return HashCodeBuilder.reflectionHashCode(this);
- }
- @Override
- public boolean equals(Object obj) {
- return EqualsBuilder.reflectionEquals(this, obj);
+ return checkSum;
}
@Override
byte[] options = getOptions();
return ((options == null) ? 0 : (options.length - getHeaderLen()));
}
- return (((Pair<Integer, Integer>) hdrFieldCoordMap.get(fieldName))
- .getRight());
+ return hdrFieldCoordMap.get(fieldName).getRight();
}
@Override
/**
* Method to perform post serialization - like computation of checksum of serialized header
- * @param serializedBytes
+ * @param data
* @return void
* @Exception throws PacketException
*/
- protected void postSerializeCustomOperation(byte[] serializedBytes)
+ protected void postSerializeCustomOperation(byte[] data)
throws PacketException {
- int startOffset = this.getfieldOffset(CHECKSUM);
- int numBits = this.getfieldnumBits(CHECKSUM);
- byte[] checkSum = BitBufferHelper.toByteArray(computeChecksum(
- serializedBytes, serializedBytes.length));
+
+ // Recompute the total length field here
+ byte[] totalLength = BitBufferHelper.toByteArray((short) data.length);
try {
- BitBufferHelper.setBytes(serializedBytes, checkSum, startOffset,
- numBits);
+ BitBufferHelper.setBytes(data, totalLength, getfieldOffset(TOTLENGTH),
+ getfieldnumBits(TOTLENGTH));
+ } catch (BufferException e) {
+ throw new PacketException(e.getMessage());
+ }
+
+ // Now compute the Header Checksum
+ byte[] checkSum = BitBufferHelper.toByteArray(computeChecksum(data, 0));
+
+ try {
+ BitBufferHelper.setBytes(data, checkSum, getfieldOffset(CHECKSUM),
+ getfieldnumBits(CHECKSUM));
} catch (BufferException e) {
throw new PacketException(e.getMessage());
}
* bytes in Total Length
* @param payload - Packet
*/
+ /**
+ * Set the total length field in the IPv4 Object
+ * Note: this field will get overwritten during serialization phase.
+ */
public void setPayload(Packet payload) {
this.payload = payload;
/*
- * Deriving the Total Lenght here
- * TODO: See if we can derive the total length during
- * another phase (during serialization/deserialization)
- * */
+ * Deriving the Total Length here
+ */
int payloadLength = 0;
try {
payloadLength = payload.serialize().length;
} catch (PacketException e) {
logger.error("", e);
}
+
this.setTotalLength((short) (this.getHeaderLen() + payloadLength));
}
- @Override
+
/**
* Method to perform post deserialization - like compare computed checksum with
* the one obtained from IP header
*/
- protected void postDeserializeCustomOperation(byte[] data, int endBitOffset) {
- int endByteOffset = endBitOffset / NetUtils.NumBitsInAByte;
- int computedChecksum = computeChecksum(data, endByteOffset);
- int actualChecksum = BitBufferHelper.getInt(fieldValues.get(CHECKSUM));
+ @Override
+ protected void postDeserializeCustomOperation(byte[] data, int startBitOffset) {
+ int start = startBitOffset / NetUtils.NumBitsInAByte;
+ short computedChecksum = computeChecksum(data, start);
+ short actualChecksum = BitBufferHelper.getShort(fieldValues.get(CHECKSUM));
if (computedChecksum != actualChecksum) {
corrupted = true;
}
package org.opendaylight.controller.sal.packet;
import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Arrays;
private static final String VALUE = "Value";
private static final int LLDPTLVFields = 3;
public static final byte[] OFOUI = new byte[] { (byte) 0x00, (byte) 0x26,
- (byte) 0xe1 }; // OpenFlow OUI
+ (byte) 0xe1 }; // OpenFlow OUI
public static final byte[] customTlvSubType = new byte[] { 0 };
public static final int customTlvOffset = OFOUI.length
+ customTlvSubType.length;
public enum TLVType {
Unknown((byte) 0), ChassisID((byte) 1), PortID((byte) 2), TTL((byte) 3), PortDesc(
(byte) 4), SystemName((byte) 5), SystemDesc((byte) 6), Custom(
- (byte) 127);
+ (byte) 127);
private byte value;
@Override
public int getfieldnumBits(String fieldName) {
if (fieldName.equals(VALUE)) {
- return (NetUtils.NumBitsInAByte * (int) BitBufferHelper.getShort(
+ return (NetUtils.NumBitsInAByte * BitBufferHelper.getShort(
fieldValues.get(LENGTH), fieldCoordinates.get(LENGTH)
- .getRight().intValue()));
+ .getRight().intValue()));
}
return fieldCoordinates.get(fieldName).getRight();
}
public int getTLVSize() {
return (LLDPTLV.fieldCoordinates.get(TYPE).getRight() + // static
LLDPTLV.fieldCoordinates.get(LENGTH).getRight() + // static
- getfieldnumBits(VALUE)); // variable
+ getfieldnumBits(VALUE)); // variable
}
/**
* @return the PortID TLV value in byte array
*/
static public byte[] createPortIDTLVValue(String portId) {
- byte[] pid = portId.getBytes();
+ byte[] pid = portId.getBytes(Charset.defaultCharset());
byte[] pidValue = new byte[pid.length + portIDSubType.length];
System.arraycopy(portIDSubType, 0, pidValue, 0, portIDSubType.length);
* @return the custom TLV value in byte array
*/
static public byte[] createCustomTLVValue(String customString) {
- byte[] customArray = customString.getBytes();
+ byte[] customArray = customString.getBytes(Charset.defaultCharset());
byte[] customValue = new byte[customTlvOffset + customArray.length];
System.arraycopy(OFOUI, 0, customValue, 0, OFOUI.length);
byte[] pidBytes = new byte[tlvLen - portIDSubType.length];
System.arraycopy(tlvValue, portIDSubType.length, pidBytes, 0,
pidBytes.length);
- return (new String(pidBytes));
+ return (new String(pidBytes, Charset.defaultCharset()));
}
/**
package org.opendaylight.controller.sal.packet;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
+import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;
* Abstract class which represents the generic network packet object It provides
* the basic methods which are common for all the packets, like serialize and
* deserialize
- *
- *
*/
public abstract class Packet {
protected Packet parent;
// The packet encapsulated by this packet
protected Packet payload;
+ // The unparsed raw payload carried by this packet
+ protected byte[] rawPayload;
// Bit coordinates of packet header fields
protected Map<String, Pair<Integer, Integer>> hdrFieldCoordMap;
// Header fields values: Map<FieldName,Value>
public Packet(boolean writeAccess) {
this.writeAccess = writeAccess;
- this.corrupted = false;
+ corrupted = false;
}
public Packet getParent() {
* @return Packet
* @throws PacketException
*/
-
public Packet deserialize(byte[] data, int bitOffset, int size)
throws PacketException {
- String hdrField;
- Integer startOffset = 0, numBits = 0;
- byte[] hdrFieldBytes;
+ // Deserialize the header fields one by one
+ int startOffset = 0, numBits = 0;
for (Entry<String, Pair<Integer, Integer>> pairs : hdrFieldCoordMap
.entrySet()) {
- hdrField = pairs.getKey();
+ String hdrField = pairs.getKey();
startOffset = bitOffset + this.getfieldOffset(hdrField);
numBits = this.getfieldnumBits(hdrField);
+ byte[] hdrFieldBytes = null;
try {
hdrFieldBytes = BitBufferHelper.getBits(data, startOffset,
numBits);
} catch (BufferException e) {
throw new PacketException(e.getMessage());
}
+
/*
* Store the raw read value, checks the payload type and set the
* payloadClass accordingly
*/
+ this.setHeaderField(hdrField, hdrFieldBytes);
+
if (logger.isTraceEnabled()) {
- logger.trace("{}: {}: {} (offset {} bitsize {})",
- new Object[] { this.getClass().getSimpleName(), hdrField,
- HexEncode.bytesToHexString(hdrFieldBytes),
- startOffset, numBits });
+ logger.trace("{}: {}: {} (offset {} bitsize {})",
+ new Object[] { this.getClass().getSimpleName(), hdrField,
+ HexEncode.bytesToHexString(hdrFieldBytes),
+ startOffset, numBits });
}
-
- this.setHeaderField(hdrField, hdrFieldBytes);
}
- postDeserializeCustomOperation(data, startOffset);
-
+ // Deserialize the payload now
int payloadStart = startOffset + numBits;
- // int payloadSize = size - payloadStart;
int payloadSize = data.length * NetUtils.NumBitsInAByte - payloadStart;
if (payloadClass != null) {
payload.deserialize(data, payloadStart, payloadSize);
payload.setParent(this);
} else {
- // For now let's discard unparsable payload
+ /*
+ * The payload class was not set, it means no class for parsing
+ * this payload is present. Let's store the raw payload if any.
+ */
+ int start = payloadStart / NetUtils.NumBitsInAByte;
+ int stop = start + payloadSize / NetUtils.NumBitsInAByte;
+ rawPayload = Arrays.copyOfRange(data, start, stop);
}
+
+
+ // Take care of computation that can be done only after deserialization
+ postDeserializeCustomOperation(data, payloadStart - getHeaderSize());
+
return this;
}
/**
- * This method serializes the header and payload bytes from the respective
+ * This method serializes the header and payload from the respective
* packet class, into a single stream of bytes to be sent on the wire
*
- * @return byte[] - serialized bytes
+ * @return The byte array representing the serialized Packet
* @throws PacketException
*/
-
public byte[] serialize() throws PacketException {
- byte[] payloadBytes = null;
- int payloadSize = 0;
- int headerSize = this.getHeaderSize();
- int payloadByteOffset = headerSize / NetUtils.NumBitsInAByte;
- int size = 0;
+ // Acquire or compute the serialized payload
+ byte[] payloadBytes = null;
if (payload != null) {
payloadBytes = payload.serialize();
- payloadSize = payloadBytes.length * NetUtils.NumBitsInAByte;
+ } else if (rawPayload != null) {
+ payloadBytes = rawPayload;
}
+ int payloadSize = (payloadBytes == null) ? 0 : payloadBytes.length;
- size = headerSize + payloadSize;
- int length = size / NetUtils.NumBitsInAByte;
- byte headerBytes[] = new byte[length];
-
- if (payload != null) {
- System.arraycopy(payloadBytes, 0, headerBytes, payloadByteOffset,
- payloadBytes.length);
+ // Allocate the buffer to contain the full (header + payload) packet
+ int headerSize = this.getHeaderSize() / NetUtils.NumBitsInAByte;
+ byte packetBytes[] = new byte[headerSize + payloadSize];
+ if (payloadBytes != null) {
+ System.arraycopy(payloadBytes, 0, packetBytes, headerSize, payloadSize);
}
- String field;
- byte[] fieldBytes;
- Integer startOffset, numBits;
-
+ // Serialize this packet header, field by field
for (Map.Entry<String, Pair<Integer, Integer>> pairs : hdrFieldCoordMap
.entrySet()) {
- field = pairs.getKey();
- fieldBytes = hdrFieldsMap.get(field);
+ String field = pairs.getKey();
+ byte[] fieldBytes = hdrFieldsMap.get(field);
// Let's skip optional fields when not set
if (fieldBytes != null) {
- startOffset = this.getfieldOffset(field);
- numBits = this.getfieldnumBits(field);
try {
- BitBufferHelper.setBytes(headerBytes, fieldBytes,
- startOffset, numBits);
+ BitBufferHelper.setBytes(packetBytes, fieldBytes,
+ getfieldOffset(field), getfieldnumBits(field));
} catch (BufferException e) {
throw new PacketException(e.getMessage());
}
}
}
- postSerializeCustomOperation(headerBytes);
+
+ // Perform post serialize operations (like checksum computation)
+ postSerializeCustomOperation(packetBytes);
if (logger.isTraceEnabled()) {
- logger.trace("{}: {}", this.getClass().getSimpleName(),
- HexEncode.bytesToHexString(headerBytes));
+ logger.trace("{}: {}", this.getClass().getSimpleName(),
+ HexEncode.bytesToHexString(packetBytes));
}
- return headerBytes;
+
+ return packetBytes;
}
/**
/**
* This method re-computes the checksum of the bits received on the wire and
* validates it with the checksum in the bits received Since the computation
- * of checksum varies based on the protocol, this method is overridden
- * Currently only IPv4 does checksum computation and validation TCP and UDP
- * need to implement these if required
+ * of checksum varies based on the protocol, this method is overridden.
+ * Currently only IPv4 and ICMP do checksum computation and validation. TCP
+ * and UDP need to implement these if required.
*
- * @param byte[] data
- * @param int endBitOffset
+ * @param byte[] data The byte stream representing the Ethernet frame
+ * @param int startBitOffset The bit offset from where the byte array corresponding to this Packet starts in the frame
* @throws PacketException
*/
- protected void postDeserializeCustomOperation(byte[] data, int endBitOffset)
+ protected void postDeserializeCustomOperation(byte[] data, int startBitOffset)
throws PacketException {
// no op
}
* @return Integer - startOffset of the requested field
*/
public int getfieldOffset(String fieldName) {
- return (((Pair<Integer, Integer>) hdrFieldCoordMap.get(fieldName))
- .getLeft());
+ return hdrFieldCoordMap.get(fieldName).getLeft();
}
/**
* @return Integer - number of bits of the requested field
*/
public int getfieldnumBits(String fieldName) {
- return (((Pair<Integer, Integer>) hdrFieldCoordMap.get(fieldName))
- .getRight());
+ return hdrFieldCoordMap.get(fieldName).getRight();
}
@Override
public String toString() {
- StringBuffer ret = new StringBuffer();
- for (Map.Entry<String, byte[]> entry : hdrFieldsMap.entrySet()) {
- ret.append(entry.getKey() + ": ");
- if (entry.getValue().length == 6) {
- ret.append(HexEncode.bytesToHexString(entry.getValue()) + " ");
- } else if (entry.getValue().length == 4) {
- try {
- ret.append(InetAddress.getByAddress(entry.getValue())
- .getHostAddress() + " ");
- } catch (UnknownHostException e) {
- logger.error("", e);
- }
- } else {
- ret.append(((Long) BitBufferHelper.getLong(entry.getValue()))
- .toString() + " ");
- }
+ StringBuilder ret = new StringBuilder();
+ ret.append(this.getClass().getSimpleName());
+ ret.append(": [");
+ for (String field : hdrFieldCoordMap.keySet()) {
+ byte[] value = hdrFieldsMap.get(field);
+ ret.append(field);
+ ret.append(": ");
+ ret.append(HexEncode.bytesToHexString(value));
+ ret.append(", ");
}
+ ret.replace(ret.length()-2, ret.length()-1, "]");
return ret.toString();
}
/**
- * Returns true if the packet is corrupted
+ * Returns the raw payload carried by this packet in case payload was not
+ * parsed. Caller can call this function in case the getPaylod() returns null.
*
- * @return boolean
+ * @return The raw payload if not parsable as an array of bytes, null otherwise
*/
- protected boolean isPacketCorrupted() {
+ public byte[] getRawPayload() {
+ return rawPayload;
+ }
+
+ /**
+ * Set a raw payload in the packet class
+ *
+ * @param payload The raw payload as byte array
+ */
+ public void setRawPayload(byte[] payload) {
+ this.rawPayload = Arrays.copyOf(payload, payload.length);
+ }
+
+ /**
+ * Return whether the deserialized packet is to be considered corrupted.
+ * This is the case when the checksum computed after reconstructing the
+ * packet received from wire is not equal to the checksum read from the
+ * stream. For the Packet class which do not have a checksum field, this
+ * function will always return false.
+ *
+ *
+ * @return true if the deserialized packet's recomputed checksum is not
+ * equal to the packet carried checksum
+ */
+ public boolean isCorrupted() {
return corrupted;
}
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result
+ + ((this.hdrFieldsMap == null) ? 0 : hdrFieldsMap.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Packet other = (Packet) obj;
+ if (hdrFieldsMap == other.hdrFieldsMap) {
+ return true;
+ }
+ if (hdrFieldsMap == null || other.hdrFieldsMap == null) {
+ return false;
+ }
+ if (hdrFieldsMap != null && other.hdrFieldsMap != null) {
+ for (String field : hdrFieldsMap.keySet()) {
+ if (!Arrays.equals(hdrFieldsMap.get(field), other.hdrFieldsMap.get(field))) {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+ return true;
+ }
+
}
*/
public class RawPacket {
private byte[] packetData;
- private LinkEncap encap;
- private TimeStamp incomingTime;
- private TimeStamp copyTime;
- private Map props;
+ private final LinkEncap encap;
+ private final TimeStamp incomingTime;
+ private final TimeStamp copyTime;
+ private Map<Object, Object> props;
private NodeConnector incomingNodeConnector;
private NodeConnector outgoingNodeConnector;
*/
public void setProps(Object key, Object value) {
if (this.props == null) {
- this.props = new HashMap();
+ this.props = new HashMap<Object, Object>();
}
this.props.put(key, value);
this.incomingTime = src.getIncomingTime();
this.incomingNodeConnector = src.getIncomingNodeConnector();
this.outgoingNodeConnector = src.getOutgoingNodeConnector();
- this.props = (src.props == null ? null : new HashMap(src.props));
+ this.props = (src.props == null ? null : new HashMap<Object, Object>(
+ src.props));
this.copyTime = new TimeStamp(System.currentTimeMillis(), "CopyTime");
}
}
/**
- * Read the timestamp when the packet has entered the system
+ * Read the time stamp when the packet has entered the system
*
- * @return The timestamp when the packet has entered the system
+ * @return The time stamp when the packet has entered the system
*/
public TimeStamp getIncomingTime() {
return this.incomingTime;
public byte[] getPacketData() {
return this.packetData;
}
+
+ /**
+ * Returns the time at which the current instance of RawPacket was created
+ * as a copy of the original one.
+ *
+ * @return The time stamp at which this RawPacket instance was created. null
+ * if this is the original instance.
+ */
+ public TimeStamp getCopyTime() {
+ return this.copyTime;
+ }
}
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
+
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
/**
* Class that represents the TCP segment objects
- *
- *
*/
public class TCP extends Packet {
}
};
- private Map<String, byte[]> fieldValues;
+ private final Map<String, byte[]> fieldValues;
/**
* Default constructor that sets all the header fields to zero
return (BitBufferHelper.getShort(fieldValues.get(DESTPORT)));
}
- @Override
- public int hashCode() {
- return HashCodeBuilder.reflectionHashCode(this);
- }
-
- @Override
- public boolean equals(Object obj) {
- return EqualsBuilder.reflectionEquals(this, obj);
- }
-
}
import java.util.LinkedHashMap;
import java.util.Map;
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
/**
* Class that represents the UDP datagram objects
- *
- *
*/
public class UDP extends Packet {
setChecksum((short) 0);
}
- private Map<String, byte[]> fieldValues;
+ private final Map<String, byte[]> fieldValues;
/* public static Map<Short, Class<? extends Packet>> decodeMap;
fieldValues.put(CHECKSUM, checksum);
return this;
}
-
- @Override
- public int hashCode() {
- return HashCodeBuilder.reflectionHashCode(this);
- }
-
- @Override
- public boolean equals(Object obj) {
- return EqualsBuilder.reflectionEquals(this, obj);
- }
}
*
*/
public class HexEncode {
- /**
- * This method converts byte array into String format without ":" inserted.
- */
+ /**
+ * This method converts byte array into String format without ":" inserted.
+ *
+ * @param bytes
+ * The byte array to convert to string
+ * @return The hexadecimal representation of the byte array. If bytes is
+ * null, "null" string is returned
+ */
public static String bytesToHexString(byte[] bytes) {
- int i;
+
+ if (bytes == null) {
+ return "null";
+ }
+
String ret = "";
- String tmp;
StringBuffer buf = new StringBuffer();
- for (i = 0; i < bytes.length; i++) {
- if (i > 0)
+ for (int i = 0; i < bytes.length; i++) {
+ if (i > 0) {
ret += ":";
- short u8byte = (short) ((short) bytes[i] & 0xff);
- tmp = Integer.toHexString(u8byte);
- if (tmp.length() == 1)
+ }
+ short u8byte = (short) (bytes[i] & 0xff);
+ String tmp = Integer.toHexString(u8byte);
+ if (tmp.length() == 1) {
buf.append("0");
+ }
buf.append(tmp);
}
ret = buf.toString();
int i = 0;
for (; i < (16 - arr.length); i++) {
buf.append("0");
- if ((i & 0x01) == 1)
+ if ((i & 0x01) == 1) {
buf.append(":");
+ }
}
for (int j = 0; j < arr.length; j++) {
buf.append(arr[j]);
- if ((((i + j) & 0x01) == 1) && (j < (arr.length - 1)))
+ if ((((i + j) & 0x01) == 1) && (j < (arr.length - 1))) {
buf.append(":");
+ }
}
return buf.toString();
}
+
public static byte[] bytesFromHexString(String values) {
- String[] octets = values.split(":");
- byte[] ret = new byte[octets.length];
- int i;
+ String target = "";
+ if (values != null) {
+ target = values;
+ }
+ String[] octets = target.split(":");
- for (i = 0; i < octets.length; i++)
+ byte[] ret = new byte[octets.length];
+ for (int i = 0; i < octets.length; i++) {
ret[i] = Integer.valueOf(octets[i], 16).byteValue();
+ }
return ret;
}
return value;
}
- /**
- * This method converts byte array into HexString format with ":" inserted.
- */
+ /**
+ * This method converts byte array into HexString format with ":" inserted.
+ */
public static String bytesToHexStringFormat(byte[] bytes) {
- int i;
+ if (bytes == null) {
+ return "null";
+ }
String ret = "";
- String tmp;
StringBuffer buf = new StringBuffer();
- for (i = 0; i < bytes.length; i++) {
- if (i > 0)
+ for (int i = 0; i < bytes.length; i++) {
+ if (i > 0) {
buf.append(":");
- short u8byte = (short) ((short) bytes[i] & 0xff);
- tmp = Integer.toHexString(u8byte);
- if (tmp.length() == 1)
+ }
+ short u8byte = (short) (bytes[i] & 0xff);
+ String tmp = Integer.toHexString(u8byte);
+ if (tmp.length() == 1) {
buf.append("0");
+ }
buf.append(tmp);
}
ret = buf.toString();
import junit.framework.Assert;
import org.junit.Test;
-import org.opendaylight.controller.sal.packet.ICMP;
public class ICMPTest {
@Test
public void testSetTypeCode() {
ICMP icmp = new ICMP();
- short icmpTypeCode = 2;
- icmp.setTypeCode(icmpTypeCode);
- byte[] typeCode = icmp.hdrFieldsMap.get("TypeCode");
- Assert.assertTrue(typeCode[0] == 0);
- Assert.assertTrue(typeCode[1] == 2);
+ byte icmpType = 2;
+ icmp.setType(icmpType);
+ byte[] typeCode = icmp.hdrFieldsMap.get("Type");
+ Assert.assertTrue(typeCode[0] == 2);
}
ICMP icmp = new ICMP();
short icmpChecksum = 200;
icmp.setChecksum(icmpChecksum);
- byte[] checksum = icmp.hdrFieldsMap.get("HeaderChecksum");
+ byte[] checksum = icmp.hdrFieldsMap.get("Checksum");
Assert.assertTrue(checksum[0] == 0);
Assert.assertTrue(checksum[1] == -56);
Assert.assertTrue(sequenceNumber[1] == -120);
}
+
+ @Test
+ public void testSerialization() throws PacketException {
+ byte icmpRawPayload[] = { (byte) 0x38, (byte) 0x26, (byte) 0x9e,
+ (byte) 0x51, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x2e, (byte) 0x6a, (byte) 0x08,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x10, (byte) 0x11, (byte) 0x12,
+ (byte) 0x13, (byte) 0x14, (byte) 0x15, (byte) 0x16,
+ (byte) 0x17, (byte) 0x18, (byte) 0x19, (byte) 0x1a,
+ (byte) 0x1b, (byte) 0x1c, (byte) 0x1d, (byte) 0x1e,
+ (byte) 0x1f, (byte) 0x20, (byte) 0x21, (byte) 0x22,
+ (byte) 0x23, (byte) 0x24, (byte) 0x25, (byte) 0x26,
+ (byte) 0x27, (byte) 0x28, (byte) 0x29, (byte) 0x2a,
+ (byte) 0x2b, (byte) 0x2c, (byte) 0x2d, (byte) 0x2e,
+ (byte) 0x2f, (byte) 0x30, (byte) 0x31, (byte) 0x32,
+ (byte) 0x33, (byte) 0x34, (byte) 0x35, (byte) 0x36, (byte) 0x37 };
+
+ short checksum = (short)0xe553;
+
+ // Create ICMP object
+ ICMP icmp = new ICMP();
+ icmp.setType((byte)8);
+ icmp.setCode((byte)0);
+ icmp.setIdentifier((short) 0x46f5);
+ icmp.setSequenceNumber((short) 2);
+ icmp.setRawPayload(icmpRawPayload);
+ //icmp.setChecksum(checksum);
+
+ // Serialize
+ byte[] stream = icmp.serialize();
+ Assert.assertTrue(stream.length == 64);
+
+ // Deserialize
+ ICMP icmpDes = new ICMP();
+ icmpDes.deserialize(stream, 0, stream.length);
+
+ Assert.assertFalse(icmpDes.isCorrupted());
+ Assert.assertTrue(icmpDes.getChecksum() == checksum);
+ Assert.assertTrue(icmp.equals(icmpDes));
+ }
}
-
/*
* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
*
package org.opendaylight.controller.sal.packet;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
import junit.framework.Assert;
import org.junit.Test;
-import org.opendaylight.controller.sal.packet.ICMP;
-import org.opendaylight.controller.sal.packet.IPv4;
-import org.opendaylight.controller.sal.packet.Packet;
+import org.opendaylight.controller.sal.utils.EtherTypes;
+import org.opendaylight.controller.sal.utils.IPProtocols;
+import org.opendaylight.controller.sal.utils.NetUtils;
public class IPv4Test {
byte[] iptotLength = { 3, -24 };
ip.hdrFieldsMap.put("TotalLength", iptotLength);
short totalLength = ip.getTotalLength();
- //System.out.println(totalLength);
Assert.assertTrue(totalLength == 1000);
}
Assert.assertTrue(protocol == 1);
Class<? extends Packet> clazz = IPv4.protocolClassMap.get(protocol);
- System.out.printf("clazz = %s\n", clazz.getName());
Assert.assertTrue(clazz == ICMP.class);
}
byte[] totalLength = ip.hdrFieldsMap.get("TotalLength");
Assert.assertTrue(totalLength[0] == 3);
Assert.assertTrue(totalLength[1] == -24);
+
+ ip.setTotalLength((short)84);
+ totalLength = ip.hdrFieldsMap.get("TotalLength");
+ Assert.assertTrue(totalLength[0] == 0);
+ Assert.assertTrue(totalLength[1] == 84);
}
@Test
Assert.assertTrue(fragmentOffset[1] == -35);
}
-
@Test
public void testSetDestinationAddress() {
IPv4 ip = new IPv4();
Assert.assertTrue(destinationAddress[3] == 110);
}
+ @Test
+ public void testChecksum() {
+ byte header[] = { (byte) 0x45, 00, 00, (byte) 0x3c, (byte) 0x1c,
+ (byte) 0x46, (byte) 0x40, 00, (byte) 0x40, 06, (byte) 0xb1,
+ (byte) 0xe6, (byte) 0xac, (byte) 0x10, (byte) 0x0a,
+ (byte) 0x63, (byte) 0xac, (byte) 0x10, (byte) 0x0a, (byte) 0x0c };
+ byte header2[] = { (byte) 0x45, 00, 00, (byte) 0x73, 00, 00,
+ (byte) 0x40, 00, (byte) 0x40, (byte) 0x11, (byte) 0xb8,
+ (byte) 0x61, (byte) 0xc0, (byte) 0xa8, 00, 01, (byte) 0xc0,
+ (byte) 0xa8, 00, (byte) 0xc7 };
+ byte header3[] = { (byte) 0x45, 00, 00, (byte) 0x47, (byte) 0x73,
+ (byte) 0x88, (byte) 0x40, 00, (byte) 0x40, 06, (byte) 0xA2,
+ (byte) 0xC4, (byte) 0x83, (byte) 0x9F, (byte) 0x0E,
+ (byte) 0x85, (byte) 0x83, (byte) 0x9F, (byte) 0x0E, (byte) 0xA1 };
+ byte header4[] = { (byte) 0x45, 00, 00, (byte) 0x54, 00, 00,
+ (byte) 0x40, 00, (byte) 0x40, 01, (byte) 0xf0, (byte) 0x8e,
+ (byte) 0xc0, (byte) 0xa8, (byte) 0x64, (byte) 0x65,
+ (byte) 0xc0, (byte) 0xa8, (byte) 0x64, (byte) 0x64 };
+ byte header5[] = { (byte) 0x45, 00, 00, (byte) 0x54, 00, 00,
+ (byte) 0x40, 00, (byte) 0x40, 01, (byte) 0xef, (byte) 0x8d,
+ (byte) 0xc0, (byte) 0xa8, (byte) 0x64, (byte) 0x65,
+ (byte) 0xc0, (byte) 0xa8, (byte) 0x65, (byte) 0x65 };
+ byte header6[] = { (byte) 0x45, 00, 00, (byte) 0x54, 00, 00,
+ (byte) 0x40, 00, (byte) 0x40, 01, (byte) 0x0b, (byte) 0x92,
+ (byte) 0xc0, (byte) 0xa8, (byte) 0x64, (byte) 0x65, (byte) 0x9,
+ (byte) 0x9, (byte) 0x1, (byte) 0x1 };
+ byte header7[] = { (byte) 0x45, 00, 00, (byte) 0x54, 00, 00,
+ (byte) 0x40, 00, (byte) 0x40, 01, (byte) 0, (byte) 0,
+ (byte) 0xc0, (byte) 0xa8, (byte) 0x64, (byte) 0x65, (byte) 0x9,
+ (byte) 0x9, (byte) 0x2, (byte) 0x2 };
+
+ IPv4 ip = new IPv4();
+
+ Assert.assertTrue(NetUtils.getUnsignedShort(ip.computeChecksum(header,
+ 0)) == 0xB1E6);
+ Assert.assertTrue(NetUtils.getUnsignedShort(ip.computeChecksum(header2,
+ 0)) == 0xb861);
+ Assert.assertTrue(NetUtils.getUnsignedShort(ip.computeChecksum(header3,
+ 0)) == 0xa2c4);
+ Assert.assertTrue(NetUtils.getUnsignedShort(ip.computeChecksum(header4,
+ 0)) == 0xf08e);
+ Assert.assertTrue(NetUtils.getUnsignedShort(ip.computeChecksum(header5,
+ 0)) == 0xef8d);
+ Assert.assertTrue(NetUtils.getUnsignedShort(ip.computeChecksum(header6,
+ 0)) == 0x0b92);
+ Assert.assertTrue(NetUtils.getUnsignedShort(ip.computeChecksum(header7,
+ 0)) == 0x0a91);
+ }
+
+ @Test
+ public void testFullIP() throws UnknownHostException, PacketException {
+ byte[] icmpRawPayload = new byte[] { (byte) 0x38, (byte) 0x26,
+ (byte) 0x9e, (byte) 0x51, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x2e, (byte) 0x6a,
+ (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x11,
+ (byte) 0x12, (byte) 0x13, (byte) 0x14, (byte) 0x15,
+ (byte) 0x16, (byte) 0x17, (byte) 0x18, (byte) 0x19,
+ (byte) 0x1a, (byte) 0x1b, (byte) 0x1c, (byte) 0x1d,
+ (byte) 0x1e, (byte) 0x1f, (byte) 0x20, (byte) 0x21,
+ (byte) 0x22, (byte) 0x23, (byte) 0x24, (byte) 0x25,
+ (byte) 0x26, (byte) 0x27, (byte) 0x28, (byte) 0x29,
+ (byte) 0x2a, (byte) 0x2b, (byte) 0x2c, (byte) 0x2d,
+ (byte) 0x2e, (byte) 0x2f, (byte) 0x30, (byte) 0x31,
+ (byte) 0x32, (byte) 0x33, (byte) 0x34, (byte) 0x35,
+ (byte) 0x36, (byte) 0x37 };
+ ICMP icmp = new ICMP();
+ icmp.setType((byte) 8);
+ icmp.setCode((byte) 0);
+ icmp.setIdentifier((short) 0x46f5);
+ icmp.setSequenceNumber((short) 2);
+ icmp.setRawPayload(icmpRawPayload);
+
+ IPv4 ip = new IPv4();
+ ip.setVersion((byte) 4);
+ ip.setIdentification((short) 5);
+ ip.setDiffServ((byte) 0);
+ ip.setECN((byte) 0);
+ ip.setTotalLength((short) 84);
+ ip.setFlags((byte) 2);
+ ip.setFragmentOffset((short) 0);
+ ip.setTtl((byte) 64);
+ ip.setProtocol(IPProtocols.ICMP.byteValue());
+ ip.setDestinationAddress(InetAddress.getByName("192.168.100.100"));
+ ip.setSourceAddress(InetAddress.getByName("192.168.100.101"));
+ ip.setPayload(icmp);
+
+ Ethernet eth = new Ethernet();
+ eth.setDestinationMACAddress(new byte[] { (byte) 0x98, (byte) 0xfc,
+ (byte) 0x11, (byte) 0x93, (byte) 0x5c, (byte) 0xb8 });
+ eth.setSourceMACAddress(new byte[] { (byte) 0x00, (byte) 0x24,
+ (byte) 0xd7, (byte) 0xa9, (byte) 0xa3, (byte) 0x50 });
+ eth.setEtherType(EtherTypes.IPv4.shortValue());
+ eth.setPayload(ip);
+
+ byte[] stream = eth.serialize();
+
+ Ethernet decEth = new Ethernet();
+ decEth.deserialize(stream, 0, stream.length * NetUtils.NumBitsInAByte);
+
+ IPv4 decIp = (IPv4) decEth.getPayload();
+ Assert.assertFalse(decIp.isCorrupted());
+ Assert.assertTrue(ip.equals(decIp));
+
+ ICMP decIcmp = (ICMP) decIp.getPayload();
+ Assert.assertFalse(decIcmp.isCorrupted());
+ Assert.assertTrue(Arrays.equals(icmpRawPayload, decIcmp.getRawPayload()));
+ }
}