}
/**
- * Returns the protocol
+ * Get the IP protocol value
*
* @return the protocol
*/
public Short getProtoNum() {
- return protocol == null ? IPProtocols.ANY.shortValue() : IPProtocols.getProtocolNumberShort(protocol);
+ return protocol == null ? null : IPProtocols.getProtocolNumberShort(protocol);
}
/**
/**
* Validate the protocol field. Either it can be a enum defined in IPProtocols.java
- * or a value between 1 and 255
+ * or a valid IP proto value between 0 and 255, see:
+ * http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
+ * for more details.
*
* @return true if a valid protocol value
*/
private boolean hasValidProtocol() {
- if (protocol != null && !protocol.isEmpty()) {
- short proto = this.getProtoNum();
- return (((proto != 0) && (proto > 0) && (proto < 256)) || protocol.equalsIgnoreCase("any"));
- }
- return true;
+ IPProtocols p = IPProtocols.fromString(protocol);
+ return p != null;
}
/**
mask = NetUtils.getInetNetworkMask(maskLen, ip instanceof Inet6Address);
match.setField(MatchType.NW_DST, ip, mask);
}
- if (this.protocol != null && !this.protocol.trim().isEmpty() && !this.protocol.equalsIgnoreCase("any")) {
- match.setField(MatchType.NW_PROTO, IPProtocols
- .getProtocolNumberByte(this.protocol));
+ if (IPProtocols.fromString(this.protocol) != IPProtocols.ANY) {
+ match.setField(MatchType.NW_PROTO, IPProtocols.getProtocolNumberByte(this.protocol));
}
if (this.tpSrc != null && !this.tpSrc.trim().isEmpty()) {
match.setField(MatchType.TP_SRC, Integer.valueOf(tpSrc).shortValue());
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),
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),
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),
HIP("HIP",139),
SHIM6("Shim6",140),
WESP("WESP",141),
- ROHC("ROHC",142);
- */
- private static final String regexDecimalString = "^[0-9]{3}$";
- private static final String regexHexString = "^(0(x|X))[0-9a-fA-F]{2}$";
+ 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;
return ((Integer) protocolNumber).byteValue();
}
+ @Override
public String toString() {
return protocolName;
}
}
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) {
return proto.toString();
}
}
+ //TODO: this is for backwards compatibility
return "0x" + Integer.toHexString(number);
}
public static short getProtocolNumberShort(String name) {
- if (name.matches(regexHexString)) {
- return Short.valueOf(Short.decode(name));
- }
- if (name.matches(regexDecimalString)) {
- return Short.valueOf(name);
+ IPProtocols p = fromString(name);
+ if (p != null) {
+ return p.shortValue();
}
- for (IPProtocols proto : IPProtocols.values()) {
- if (proto.protocolName.equalsIgnoreCase(name)) {
- return proto.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(regexHexString)) {
- return Integer.valueOf(Integer.decode(name));
- }
- if (name.matches(regexDecimalString)) {
- 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(regexHexString)) {
- return Integer.valueOf(Integer.decode(name)).byteValue();
+ IPProtocols p = fromString(name);
+ if (p != null) {
+ return p.byteValue();
}
- if (name.matches(regexDecimalString)) {
- return Integer.valueOf(name).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() {
}
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;
+ }
+
+ }
+ }
}
--- /dev/null
+/**
+ *
+ */
+package org.opendaylight.controller.sal.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+/**
+ * @author ykhodork
+ *
+ */
+public class IPProtocolsTest {
+
+ static short shortVal = 1;
+ static int intVal = 1;
+ static byte byteVal = 1;
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#getProtocolName(int)}.
+ */
+ @Test
+ public void testGetProtocolNameInt() {
+ assertEquals("ICMP", IPProtocols.getProtocolName(1));
+ assertEquals("0x4d2", IPProtocols.getProtocolName(1234));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#getProtocolName(short)}.
+ */
+ @Test
+ public void testGetProtocolNameShort() {
+ assertEquals("ICMP", IPProtocols.getProtocolName(shortVal));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#getProtocolName(byte)}.
+ */
+ @Test
+ public void testGetProtocolNameByte() {
+ assertEquals("ICMP", IPProtocols.getProtocolName(byteVal));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#getProtocolNumberShort(java.lang.String)}.
+ */
+ @Test
+ public void testGetProtocolNumberShort() {
+ assertEquals(shortVal, IPProtocols.getProtocolNumberShort("ICMP"));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#getProtocolNumberInt(java.lang.String)}.
+ */
+ @Test
+ public void testGetProtocolNumberInt() {
+ assertEquals(intVal, IPProtocols.getProtocolNumberInt("ICMP"));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#getProtocolNumberByte(java.lang.String)}.
+ */
+ @Test
+ public void testGetProtocolNumberByte() {
+ assertEquals(byteVal, IPProtocols.getProtocolNumberByte("ICMP"));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#fromString(java.lang.String)}.
+ */
+ @Test
+ public void testFromString() {
+ assertTrue(null == IPProtocols.fromString("Not a protocol"));
+ assertTrue(null == IPProtocols.fromString("0xFFF"));
+ assertTrue(null == IPProtocols.fromString("-2"));
+
+ assertTrue(IPProtocols.ANY == IPProtocols.fromString("any"));
+ assertTrue(IPProtocols.ANY == IPProtocols.fromString("ANY"));
+ assertTrue(IPProtocols.ANY == IPProtocols.fromString("*"));
+ assertTrue(IPProtocols.ANY == IPProtocols.fromString(null));
+
+ assertTrue(IPProtocols.TCP == IPProtocols.fromString("TCP"));
+ assertTrue(IPProtocols.TCP == IPProtocols.fromString("tcp"));
+ assertTrue(IPProtocols.UDP == IPProtocols.fromString("0x11"));
+ assertTrue(IPProtocols.UDP == IPProtocols.fromString("0X11"));
+
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+