Merge "Fix: IPProtocols not parsing correctly"
[controller.git] / opendaylight / sal / api / src / main / java / org / opendaylight / controller / sal / utils / IPProtocols.java
index cdb4463c02acb2636a0991053f9e64951e3f3ba5..d3d3142cdfbcf7f06dc81d5cd49d95f0038ee971 100644 (file)
@@ -13,24 +13,25 @@ import java.util.ArrayList;
 import java.util.List;
 
 /**
- * It represents the most common IP protocols numbers
- * It provides the binding between IP protocol names and numbers
- * and provides APIs to read and parse them in either of the two forms
- *
+ * Enum represents the most common IP protocols numbers It provides the binding
+ * between IP protocol names and numbers and provides APIs to read and parse
+ * them in either of the two forms
  *
+ * NOTE: Openflow 1.0 supports the IP Proto match only for ICMP, TCP and UDP
  *
+ * references:
+ * http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
  */
-// Openflow 1.0 supports the IP Proto match only for ICMP, TCP and UDP
 public enum IPProtocols {
-    ANY("any", 0),
-    /*  HOPOPT("HOPOPT",0),
-     */ICMP("ICMP", 1),
-    /*  IGMP("IGMP",2),
+     ANY("any", -1),
+     HOPOPT("HOPOPT",0),
+     ICMP("ICMP", 1),
+     IGMP("IGMP",2),
      GGP("GGP",3),
      IPV4("IPv4",4),
      ST("ST",5),
-     */TCP("TCP", 6),
-    /*  CBT("CBT",7),
+     TCP("TCP", 6),
+     CBT("CBT",7),
      EGP("EGP",8),
      IGP("IGP",9),
      BBNRCCMON("BBN-RCC-MON",10),
@@ -40,8 +41,8 @@ public enum IPProtocols {
      EMCON("EMCON",14),
      XNET("XNET",15),
      CHAOS("CHAOS",16),
-     */UDP("UDP", 17),
-    /*  MUX("MUX",18),
+     UDP("UDP", 17),
+     MUX("MUX",18),
      DCNMEAS("DCN-MEAS",19),
      HMP("HMP",20),
      PRM("PRM",21),
@@ -81,8 +82,8 @@ public enum IPProtocols {
      MOBILE("MOBILE",55),
      TLSP("TLSP",56),
      SKIP("SKIP",57),
-     */IPV6ICMP("IPv6-ICMP", 58);
-    /*  IPV6NoNxt("IPv6-NoNxt",59),
+     IPV6ICMP("IPv6-ICMP", 58),
+     IPV6NoNxt("IPv6-NoNxt",59),
      IPV6Opts("IPv6-Opts",60),
      ANYHOST("ANY-HOST",61),
      CFTP("CFTP",62),
@@ -166,9 +167,15 @@ public enum IPProtocols {
      HIP("HIP",139),
      SHIM6("Shim6",140),
      WESP("WESP",141),
-     ROHC("ROHC",142);
-     */
-    private static final String regexNumberString = "^[0-9]+$";
+     ROHC("ROHC",142),
+     /*143-252 Unassigned by IANA*/
+
+     //Experimebtal protocol numbers (http://tools.ietf.org/html/rfc3692)
+     EXP1("Experimental1", 253),
+     EXP2("Experimental2", 254),
+
+     RESERVED("RESERVED",255);
+
     private String protocolName;
     private int protocolNumber;
 
@@ -189,6 +196,7 @@ public enum IPProtocols {
         return ((Integer) protocolNumber).byteValue();
     }
 
+    @Override
     public String toString() {
         return protocolName;
     }
@@ -198,11 +206,11 @@ public enum IPProtocols {
     }
 
     public static String getProtocolName(short number) {
-        return getProtocolNameInternal((int) number & 0xffff);
+        return getProtocolNameInternal(number & 0xffff);
     }
 
     public static String getProtocolName(byte number) {
-        return getProtocolNameInternal((int) number & 0xff);
+        return getProtocolNameInternal(number & 0xff);
     }
 
     private static String getProtocolNameInternal(int number) {
@@ -211,43 +219,35 @@ public enum IPProtocols {
                 return proto.toString();
             }
         }
+        //TODO: this is for backwards compatibility
         return "0x" + Integer.toHexString(number);
     }
 
     public static short getProtocolNumberShort(String name) {
-        if (name.matches(regexNumberString)) {
-            return Short.valueOf(name);
-        }
-        for (IPProtocols proto : IPProtocols.values()) {
-            if (proto.protocolName.equalsIgnoreCase(name)) {
-                return proto.shortValue();
-            }
+        IPProtocols p = fromString(name);
+        if (p != null) {
+            return p.shortValue();
         }
-        return 0;
+        //This method should be called after validation only
+        throw new IllegalArgumentException("Illegal IP protocol value: " + name);
     }
 
     public static int getProtocolNumberInt(String name) {
-        if (name.matches(regexNumberString)) {
-            return Integer.valueOf(name);
-        }
-        for (IPProtocols proto : IPProtocols.values()) {
-            if (proto.protocolName.equalsIgnoreCase(name)) {
-                return proto.intValue();
-            }
+        IPProtocols p = fromString(name);
+        if (p != null) {
+            return p.intValue();
         }
-        return 0;
+        //This method should be called after validation only
+        throw new IllegalArgumentException("Illegal IP protocol value: " + name);
     }
 
     public static byte getProtocolNumberByte(String name) {
-        if (name.matches(regexNumberString)) {
-            return Integer.valueOf(name).byteValue();
+        IPProtocols p = fromString(name);
+        if (p != null) {
+            return p.byteValue();
         }
-        for (IPProtocols proto : IPProtocols.values()) {
-            if (proto.protocolName.equalsIgnoreCase(name)) {
-                return proto.byteValue();
-            }
-        }
-        return 0;
+        //This method should be called after validation only
+        throw new IllegalArgumentException("Illegal IP protocol value: " + name);
     }
 
     public static List<String> getProtocolNameList() {
@@ -257,4 +257,47 @@ public enum IPProtocols {
         }
         return protoList;
     }
+
+    /**
+     * Method to parse an IPProtocol from a numeric string
+     * (see: {@link Java.Lang.Integer.decode(java.lang.String)} for parsable strings),
+     * or this enum's name string.
+     *
+     * @param s
+     *            The IP protocol string to be parsed
+     * @return The IP protocol Enum, or null if invalid protocol string is passed
+     */
+    public static IPProtocols fromString(String s) {
+        // null/empty/any/* evaluates to ANY
+        if (s == null || s.isEmpty() || s.equalsIgnoreCase("any") || s.equals("*")) {
+            return IPProtocols.ANY;
+        }
+
+        // Try parsing numeric and find the related ENUM
+        try {
+            int protoNum = Integer.decode(s);
+            for (IPProtocols protoEnum : IPProtocols.values()) {
+                if (protoEnum.protocolNumber == protoNum) {
+                    return protoEnum;
+                }
+            }
+            // At this point it's an invalid number (i.e. out of range or not a valid proto num)
+            return null;
+        } catch (NumberFormatException nfe) {
+            // numeric failed try by NAME
+            try {
+                return valueOf(s);
+            } catch(IllegalArgumentException e) {
+                // Neither numeric nor enum NAME, attempt human readable name
+                for (IPProtocols protoEnum : IPProtocols.values()) {
+                    if (protoEnum.toString().equalsIgnoreCase(s)) {
+                        return protoEnum;
+                    }
+                }
+                //couldn't parse, signifies an invalid proto field!
+                return null;
+            }
+
+        }
+    }
 }