Merge "Introducing the Modification classses"
[controller.git] / opendaylight / sal / api / src / main / java / org / opendaylight / controller / sal / packet / IPv4.java
index 44318aab8c5c1626eb787b960acfaa3ede7bea29..3363f423d695f1b2f090e6c5274715f47d765e3c 100644 (file)
@@ -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,
@@ -20,6 +20,8 @@ import java.util.Random;
 
 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;
@@ -47,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<Byte, Class<? extends Packet>> protocolClassMap;
     static {
         protocolClassMap = new HashMap<Byte, Class<? extends Packet>>();
@@ -145,12 +151,7 @@ public class IPv4 extends Packet {
     public int getHeaderSize() {
         int headerLen = this.getHeaderLen();
         if (headerLen == 0) {
-            headerLen = 20;
-        }
-
-        byte[] options = hdrFieldsMap.get(OPTIONS);
-        if (options != null) {
-            headerLen += options.length;
+            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,8 +439,23 @@ 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;
@@ -444,7 +464,7 @@ public class IPv4 extends Packet {
     /**
      * Computes the IPv4 header checksum on the passed stream of bytes
      * representing the packet
-     * 
+     *
      * @param data
      *            The byte stream
      * @param offset
@@ -455,7 +475,7 @@ public class IPv4 extends Packet {
         int end = start + getHeaderLen();
         short checkSum = (short) 0;
         int sum = 0, carry = 0, finalSum = 0;
-        int parsedHex = 0;
+        int wordData;
         int checksumStart = start
                 + (getfieldOffset(CHECKSUM) / NetUtils.NumBitsInAByte);
 
@@ -464,14 +484,8 @@ public class IPv4 extends Packet {
             if (i == checksumStart) {
                 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]));
-            }
-
-            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;
@@ -483,15 +497,13 @@ public class IPv4 extends Packet {
     @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 hdrFieldCoordMap.get(fieldName).getRight();
     }
@@ -567,4 +579,12 @@ public class IPv4 extends Packet {
             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());
+    }
 }