Fixed a bug that failed specifying the value 0 on VLAN ID field for a match condition...
[controller.git] / opendaylight / sal / api / src / main / java / org / opendaylight / controller / sal / match / MatchType.java
index 8379f073dc8f34e3f3744fd6072ca0969bbdf3fa..1c964267b130d8b9f82d5e3726cc446683dbc4bd 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -9,42 +8,45 @@
 
 package org.opendaylight.controller.sal.match;
 
+import java.net.Inet4Address;
 import java.net.InetAddress;
+import java.util.Arrays;
 
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.utils.HexEncode;
+import org.opendaylight.controller.sal.utils.NetUtils;
 
 /**
- * Represents the binding between the id, the value and mask type and the range values
- * of the elements type that can be matched on the network frame/packet/message
- *
- *
- *
+ * Represents the binding between the id, the value and mask type and the range
+ * values of the elements type that can be matched on the network
+ * frame/packet/message
  */
 public enum MatchType {
-    IN_PORT("inPort", 1 << 0, NodeConnector.class, 1, 0), 
-    DL_SRC("dlSrc", 1 << 1, Byte[].class, 0, 0xffffffffffffL), 
-    DL_DST("dlDst", 1 << 2, Byte[].class, 0, 0xffffffffffffL), 
-    DL_VLAN("dlVlan", 1 << 3, Short.class, 2, 0xfff), // 2 bytes
+    IN_PORT("inPort", 1 << 0, NodeConnector.class, 1, 0),
+    DL_SRC("dlSrc", 1 << 1, Byte[].class, 0, 0xffffffffffffL),
+    DL_DST("dlDst", 1 << 2, Byte[].class, 0, 0xffffffffffffL),
+    DL_VLAN("dlVlan", 1 << 3, Short.class, 0, 0xfff), // 2 bytes
     DL_VLAN_PR("dlVlanPriority", 1 << 4, Byte.class, 0, 0x7), // 3 bits
-    DL_OUTER_VLAN("dlOuterVlan", 1 << 5, Short.class, 2, 0xfff), 
-    DL_OUTER_VLAN_PR("dlOuterVlanPriority", 1 << 6, Short.class, 0, 0x7), 
+    DL_OUTER_VLAN("dlOuterVlan", 1 << 5, Short.class, 1, 0xfff),
+    DL_OUTER_VLAN_PR("dlOuterVlanPriority", 1 << 6, Short.class, 0, 0x7),
     DL_TYPE("dlType", 1 << 7, Short.class, 0, 0xffff), // 2 bytes
-    NW_TOS("nwTOS", 1 << 8, Byte.class, 0, 0xff), // 1 byte
+    NW_TOS("nwTOS", 1 << 8, Byte.class, 0, 0x3f), // 6 bits (DSCP field)
     NW_PROTO("nwProto", 1 << 9, Byte.class, 0, 0xff), // 1 byte
-    NW_SRC("nwSrc", 1 << 10, InetAddress.class, 0, 0), 
-    NW_DST("nwDst", 1 << 11, InetAddress.class, 0, 0), 
+    NW_SRC("nwSrc", 1 << 10, InetAddress.class, 0, 0),
+    NW_DST("nwDst", 1 << 11, InetAddress.class, 0, 0),
     TP_SRC("tpSrc", 1 << 12, Short.class, 1, 0xffff), // 2 bytes
     TP_DST("tpDst", 1 << 13, Short.class, 1, 0xffff); // 2 bytes
 
+    // Used to indicate that no VLAN ID is set.
+    public static final short DL_VLAN_NONE = (short) 0;
+
     private String id;
     private int index;
     private Class<?> dataType;
     private long minValue;
     private long maxValue;
 
-    private MatchType(String id, int index, Class<?> dataType, long minValue,
-            long maxValue) {
+    private MatchType(String id, int index, Class<?> dataType, long minValue, long maxValue) {
         this.id = id;
         this.index = index;
         this.dataType = dataType;
@@ -65,12 +67,12 @@ public enum MatchType {
     }
 
     public String getRange() {
-        return "[0x" + Long.toHexString(minValue) + "-0x"
-                + Long.toHexString(maxValue) + "]";
+        return "[0x" + Long.toHexString(minValue) + "-0x" + Long.toHexString(maxValue) + "]";
     }
 
     /**
-     *  Perform the assignment type validation
+     * Perform the assignment type validation
+     *
      * @param value
      * @param mask
      * @return
@@ -84,7 +86,8 @@ public enum MatchType {
         Class<?> e = this.dataType();
         Class<?> g = value.getClass();
 
-        // This is all what we need, if value type is same of match required type
+        // This is all what we need, if value type is same of match required
+        // type
         if (g.equals(e)) {
             return true;
         }
@@ -115,6 +118,7 @@ public enum MatchType {
 
     /**
      * Perform the value and mask range validation
+     *
      * @param value
      * @param mask
      * @return
@@ -141,13 +145,11 @@ public enum MatchType {
             val = ((Integer) value).intValue();
             msk = (mask != null) ? ((Integer) mask).intValue() : 0;
 
-        } else if (value.getClass() == Short.class
-                || value.getClass() == short.class) {
+        } else if (value.getClass() == Short.class || value.getClass() == short.class) {
             val = ((Short) value).intValue() & 0xffff;
             msk = (mask != null) ? ((Short) mask).intValue() & 0xffff : 0;
 
-        } else if (value.getClass() == Byte.class
-                || value.getClass() == byte.class) {
+        } else if (value.getClass() == Byte.class || value.getClass() == byte.class) {
             val = ((Byte) value).intValue() & 0xff;
             msk = (mask != null) ? ((Byte) mask).intValue() & 0xff : 0;
         }
@@ -157,12 +159,13 @@ public enum MatchType {
 
     /**
      * Return the mask value in 64 bits bitmask form
+     *
      * @param mask
      * @return
      */
     public long getBitMask(Object mask) {
         if (this.dataType == InetAddress.class) {
-            //TODO handle Inet v4 and v6 v6 will have a second upper mask
+            // TODO handle Inet v4 and v6 v6 will have a second upper mask
             return 0;
         }
         if (this.dataType() == Byte[].class) {
@@ -172,14 +175,12 @@ public enum MatchType {
             byte mac[] = (byte[]) mask;
             long bitmask = 0;
             for (short i = 0; i < 6; i++) {
-                //                             bitmask |= (((long)mac[i] & 0xffL) << (long)((5-i)*8));
-                bitmask |= (((long) mac[i] & 0xffL) << ((5 - i) * 8));
+                bitmask |= ((mac[i] & 0xffL) << ((5 - i) * 8));
             }
             return bitmask;
         }
         if (this.dataType == Integer.class || this.dataType == int.class) {
-            return (mask == null) ? this.maxValue : ((Integer) mask)
-                    .longValue();
+            return (mask == null) ? this.maxValue : ((Integer) mask).longValue();
 
         }
         if (this.dataType == Short.class || this.dataType == short.class) {
@@ -192,31 +193,127 @@ public enum MatchType {
         return 0L;
     }
 
-       public String stringify(Object value) {
-               if (value == null) {
-                       return null;
-               }
-               
-               switch (this) {
-               case DL_DST:
-               case DL_SRC:
-                       return HexEncode.bytesToHexStringFormat((byte[])value);
-               case DL_TYPE:
-               case DL_VLAN:
-                       if ((Short)value < 0) {
-                               return ((Integer) (((Short)value).intValue() & 0x7FFF | 0x8000)).toString();
-                       }
-                       break;
-               case NW_SRC:
-               case NW_DST:
-                       return ((InetAddress)value).getHostAddress();
-               case TP_SRC:
-               case TP_DST:
-                       if ((Short)value < 0) {
-                               return ((Integer) (((Short)value).intValue() & 0x7FFF | 0x8000)).toString();
-                       }
-                       break;
-               }
-               return value.toString();
-       }
+    public String stringify(Object value) {
+        if (value == null) {
+            return null;
+        }
+
+        switch (this) {
+        case DL_DST:
+        case DL_SRC:
+            return HexEncode.bytesToHexStringFormat((byte[]) value);
+        case DL_TYPE:
+        case DL_VLAN:
+            return ((Integer) NetUtils.getUnsignedShort((Short) value)).toString();
+        case NW_SRC:
+        case NW_DST:
+            return ((InetAddress) value).getHostAddress();
+        case NW_TOS:
+            return ((Integer) NetUtils.getUnsignedByte((Byte) value)).toString();
+        case TP_SRC:
+        case TP_DST:
+            return ((Integer) NetUtils.getUnsignedShort((Short) value)).toString();
+        default:
+            break;
+        }
+        return value.toString();
+    }
+
+    public int valueHashCode(Object o) {
+        if (o == null) {
+            return 0;
+        }
+        switch (this) {
+        case DL_SRC:
+        case DL_DST:
+            return NetUtils.byteArray4ToInt((byte[])o);
+        default:
+            return o.hashCode();
+        }
+    }
+
+    public int hashCode(Object v, Object m) {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + this.hashCode();
+
+        switch (this) {
+        case DL_SRC:
+        case DL_DST:
+            result = prime * result + ((v == null)? 0 : NetUtils.byteArray4ToInt((byte[])v));
+            result = prime * result + ((m == null)? 0 : NetUtils.byteArray4ToInt((byte[])m));
+            break;
+        case NW_SRC:
+        case NW_DST:
+            // Hash code has to take into account only prefix address
+            InetAddress ip = (InetAddress) v;
+            int maskLen = (m == null) ? ((ip instanceof Inet4Address) ? 32 : 128) : NetUtils
+                    .getSubnetMaskLength((InetAddress) m);
+            InetAddress prefix = NetUtils.getSubnetPrefix(ip, maskLen);
+            result = prime * result + ((v == null)? 0 : prefix.hashCode());
+            break;
+        default:
+            result = prime * result + ((v == null)? 0 : v.hashCode());
+            result = prime * result + ((m == null)? 0 : m.hashCode());
+        }
+        return result;
+    }
+    public boolean equalValues(Object a, Object b) {
+        if (a == b) {
+            return true;
+        }
+        if (a == null || b == null) {
+            return false;
+        }
+        switch (this) {
+        case DL_DST:
+        case DL_SRC:
+            return Arrays.equals((byte[]) a, (byte[]) b);
+        default:
+            return a.equals(b);
+        }
+    }
+
+    public boolean equalMasks(Object a, Object b) {
+        if (a == b) {
+            return true;
+        }
+        switch (this) {
+        case NW_SRC:
+        case NW_DST:
+            /*
+             * For network address mask, network node may return full mask for
+             * flows the controller generated with a null mask object
+             */
+            if (a == null || b == null) {
+                InetAddress mask = (a == null) ? (InetAddress) b : (InetAddress) a;
+                int maxLength = (mask instanceof Inet4Address) ? 32 : 128;
+                return (NetUtils.getSubnetMaskLength(mask) == maxLength);
+            }
+        default:
+            if (a == null) {
+                return false;
+            }
+            return a.equals(b);
+        }
+    }
+
+    public boolean equals(Object value1, Object value2, Object mask1, Object mask2) {
+        switch (this) {
+        case NW_SRC:
+        case NW_DST:
+            // Equality to be checked against prefix addresses
+            InetAddress thisIP = (InetAddress) value1;
+            int thisMaskLen = (mask1 == null) ? ((thisIP instanceof Inet4Address) ? 32 : 128) : NetUtils
+                    .getSubnetMaskLength((InetAddress) mask1);
+            InetAddress otherIP = (InetAddress) value2;
+            int otherMaskLen = (mask2 == null) ? ((otherIP instanceof Inet4Address) ? 32 : 128) : NetUtils
+                    .getSubnetMaskLength((InetAddress) mask2);
+
+            return NetUtils.getSubnetPrefix(thisIP, thisMaskLen)
+                    .equals(NetUtils.getSubnetPrefix(otherIP, otherMaskLen));
+        default:
+            return (this.equalValues(value1, value2) && this.equalMasks(mask1, mask2));
+        }
+    }
 }