X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fsal%2Fapi%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Fpacket%2FIPv4.java;h=3363f423d695f1b2f090e6c5274715f47d765e3c;hp=d547e2c905ecae0d5397a053d9c784a3f64a2aea;hb=c1362c86eb19e92e6c64d10099a45deb499c6db1;hpb=340a93f17c03395391339a82b3a036afd374f569 diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/IPv4.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/IPv4.java index d547e2c905..3363f423d6 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/IPv4.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/IPv4.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2013-2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, @@ -18,10 +18,10 @@ import java.util.LinkedHashMap; 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.match.Match; +import org.opendaylight.controller.sal.match.MatchType; import org.opendaylight.controller.sal.utils.IPProtocols; import org.opendaylight.controller.sal.utils.NetUtils; import org.slf4j.Logger; @@ -29,13 +29,11 @@ import org.slf4j.LoggerFactory; /** * 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"; @@ -51,6 +49,10 @@ public class IPv4 extends Packet { private static final String DIP = "DestinationIPAddress"; private static final String OPTIONS = "Options"; + private static final int UNIT_SIZE_SHIFT = 2; + private static final int UNIT_SIZE = (1 << UNIT_SIZE_SHIFT); + private static final int MIN_HEADER_SIZE = 20; + public static final Map> protocolClassMap; static { protocolClassMap = new HashMap>(); @@ -78,7 +80,8 @@ public class IPv4 extends Packet { } }; - private Map fieldValues; + private final Map fieldValues; + /** * Default constructor that sets the version to 4, headerLength to 5, @@ -90,14 +93,15 @@ public class IPv4 extends Packet { fieldValues = new HashMap(); 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); } /** @@ -112,14 +116,15 @@ public class IPv4 extends Packet { fieldValues = new HashMap(); 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); } /** @@ -139,21 +144,17 @@ public class IPv4 extends Packet { } /** - * 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) - headerLen = 20; - - byte[] options = hdrFieldsMap.get(OPTIONS); - if (options != null) - headerLen += options.length; + if (headerLen == 0) { + headerLen = MIN_HEADER_SIZE; + } return headerLen * NetUtils.NumBitsInAByte; - } /** @@ -260,6 +261,10 @@ public class IPv4 extends Packet { public void setHeaderField(String headerField, byte[] readValue) { if (headerField.equals(PROTOCOL)) { payloadClass = protocolClassMap.get(readValue[0]); + } else if (headerField.equals(OPTIONS) && + (readValue == null || readValue.length == 0)) { + hdrFieldsMap.remove(headerField); + return; } hdrFieldsMap.put(headerField, readValue); } @@ -276,7 +281,7 @@ public class IPv4 extends Packet { } /** - * Stores the length of IP header in words (2 bytes) + * Stores the length of IP header in words (4 bytes) * @param headerLength the headerLength to set * @return IPv4 */ @@ -378,9 +383,9 @@ public class IPv4 extends Packet { * @param checksum the checksum to set */ /*public IPv4 setChecksum() { - short ipChecksum = computeChecksum(); + short ipChecksum = computeChecksum(); byte[] checksum = BitBufferHelper.toByteArray(ipChecksum); - fieldValues.put(CHECKSUM, checksum); + fieldValues.put(CHECKSUM, checksum); return this; }*/ @@ -434,88 +439,100 @@ public class IPv4 extends Packet { * @return IPv4 */ public IPv4 setOptions(byte[] options) { - fieldValues.put(OPTIONS, options); - byte newIHL = (byte) (5 + options.length); + byte newIHL = (byte)(MIN_HEADER_SIZE >>> UNIT_SIZE_SHIFT); + if (options == null || options.length == 0) { + fieldValues.remove(OPTIONS); + } else { + int len = options.length; + int rlen = (len + (UNIT_SIZE - 1)) & ~(UNIT_SIZE - 1); + if (rlen > len) { + // Padding is required. + byte[] newopt = new byte[rlen]; + System.arraycopy(options, 0, newopt, 0, len); + options = newopt; + len = rlen; + } + fieldValues.put(OPTIONS, options); + newIHL += (len >>> UNIT_SIZE_SHIFT); + } + setHeaderLength(newIHL); return this; } /** - * 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 wordData; + 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])); - - parsedHex = Integer.valueOf(sbuffer.toString(), 16); - sum += parsedHex; + } + wordData = ((data[i] << 8) & 0xFF00) + (data[i + 1] & 0xFF); + sum = sum + wordData; } 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 /** * Gets the number of bits for the fieldname specified - * If the fieldname has variable length like "Options", then this value is computed using the - * options length and the header length + * If the fieldname has variable length like "Options", then this value is computed using the header length * @param fieldname - String * @return number of bits for fieldname - int */ public int getfieldnumBits(String fieldName) { if (fieldName.equals(OPTIONS)) { - byte[] options = getOptions(); - return ((options == null) ? 0 : (options.length - getHeaderLen())); + return (getHeaderLen() - MIN_HEADER_SIZE) * NetUtils.NumBitsInAByte; } - return (((Pair) 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(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(serializedBytes, checkSum, startOffset, - numBits); + BitBufferHelper.setBytes(data, checkSum, getfieldOffset(CHECKSUM), + getfieldnumBits(CHECKSUM)); } catch (BufferException e) { throw new PacketException(e.getMessage()); } @@ -527,33 +544,47 @@ public class IPv4 extends Packet { * 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); + if (payload != null) { + 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; } } + + @Override + public void populateMatch(Match match) { + match.setField(MatchType.NW_SRC, NetUtils.getInetAddress(this.getSourceAddress())); + match.setField(MatchType.NW_DST, NetUtils.getInetAddress(this.getDestinationAddress())); + match.setField(MatchType.NW_PROTO, this.getProtocol()); + match.setField(MatchType.NW_TOS, this.getDiffServ()); + } }