Merge "Remove powermock dependency from md-sal."
[controller.git] / opendaylight / containermanager / api / src / main / java / org / opendaylight / controller / containermanager / ContainerFlowConfig.java
index 488f8928de478ec8faab7122d93fd8f21cda0a62..6abd1acd404956db9f3c0819109154ac85b1717d 100644 (file)
@@ -15,13 +15,16 @@ import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
+import org.opendaylight.controller.configuration.ConfigurationObject;
 import org.opendaylight.controller.sal.match.Match;
 import org.opendaylight.controller.sal.match.MatchType;
 import org.opendaylight.controller.sal.packet.BitBufferHelper;
@@ -42,19 +45,20 @@ import org.slf4j.LoggerFactory;
  */
 @XmlRootElement (name = "flow-spec-config")
 @XmlAccessorType(XmlAccessType.NONE)
-public class ContainerFlowConfig implements Serializable {
+public class ContainerFlowConfig extends ConfigurationObject implements Serializable {
     private static Logger log = LoggerFactory.getLogger(ContainerFlowConfig.class);
 
     /** The Constant serialVersionUID. */
     private static final long serialVersionUID = 1L;
 
-    /** The Constant regexName. */
-    private static final String regexName = "^[\\w-+.@]+$";
-
     /** Flow Spec name. */
     @XmlElement
     private String name;
 
+    /** The vlan. */
+    @XmlElement
+    private String dlVlan;
+
     /** The network Source. */
     @XmlElement
     private String nwSrc;
@@ -101,6 +105,7 @@ public class ContainerFlowConfig implements Serializable {
     public ContainerFlowConfig(String name, String srcIP, String dstIP, String proto, String srcPort,
             String dstPort) {
         this.name = name;
+        this.dlVlan = null;
         this.nwSrc = srcIP;
         this.nwDst = dstIP;
         this.protocol = proto;
@@ -109,9 +114,21 @@ public class ContainerFlowConfig implements Serializable {
         //this.unidirectional = false;
     }
 
+    public ContainerFlowConfig(String name, String dlVlan, String srcIP, String dstIP, String proto, String srcPort,
+            String dstPort) {
+        this.name = name;
+        this.dlVlan = dlVlan;
+        this.nwSrc = srcIP;
+        this.nwDst = dstIP;
+        this.protocol = proto;
+        this.tpSrc = srcPort;
+        this.tpDst = dstPort;
+    }
+
 
     public ContainerFlowConfig(ContainerFlowConfig containerFlowConfig) {
         this.name = containerFlowConfig.name;
+        this.dlVlan = containerFlowConfig.dlVlan;
         this.nwSrc = containerFlowConfig.nwSrc;
         this.nwDst = containerFlowConfig.nwDst;
         this.protocol = containerFlowConfig.protocol;
@@ -130,6 +147,15 @@ public class ContainerFlowConfig implements Serializable {
         return name;
     }
 
+    /**
+     * Returns the vlan id.
+     *
+     * @return the Vlan Id
+     */
+    public String getVlan() {
+        return (dlVlan == null || dlVlan.isEmpty()) ? null : dlVlan;
+    }
+
     /**
      * Returns the Source IP Address.
      *
@@ -192,6 +218,7 @@ public class ContainerFlowConfig implements Serializable {
         result = prime * result
                 + ((protocol == null) ? 0 : protocol.hashCode());
         result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + ((dlVlan == null) ? 0 : dlVlan.hashCode());
         result = prime * result + ((nwDst == null) ? 0 : nwDst.hashCode());
         result = prime * result + ((tpDst == null) ? 0 : tpDst.hashCode());
         result = prime * result + ((nwSrc == null) ? 0 : nwSrc.hashCode());
@@ -221,7 +248,7 @@ public class ContainerFlowConfig implements Serializable {
             return false;
         }
         ContainerFlowConfig other = (ContainerFlowConfig) obj;
-        if (matchName(other) && matchSrcIP(other)
+        if (matchName(other) && matchDlVlan(other) && matchSrcIP(other)
                 && matchDstIP(other) && matchProtocol(other)
                 && matchSrcPort(other) && matchDstPort(other)) {
             return true;
@@ -280,6 +307,23 @@ public class ContainerFlowConfig implements Serializable {
         return name.equals(flowSpec.name);
     }
 
+    /**
+     * Match the set of these vlans with that of flowSpec's vlans.
+     *
+     * @param flowSpec
+     *            Flow Specification
+     * @return true, if successful
+     */
+    private boolean matchDlVlan(ContainerFlowConfig flowSpec) {
+        if (dlVlan == flowSpec.dlVlan) {
+            return true;
+        }
+        if (dlVlan == null || flowSpec.dlVlan == null) {
+            return false;
+        }
+
+        return this.getVlanList().equals(flowSpec.getVlanList());
+    }
 
     /**
      * Match Source IP Address.
@@ -361,6 +405,37 @@ public class ContainerFlowConfig implements Serializable {
         return this.tpDst.equals(flowSpec.tpDst);
     }
 
+    /**
+     * Returns the vlan id number for all vlans specified
+     *
+     * @return the vlan id number for all vlans specified
+     */
+    public Set<Short> getVlanList() {
+        /*
+         * example: Vlan = "1,3,5-12"
+         * elemArray = ["1" "3" "5-12"]
+         * elem[2] = "5-12" --> limits = ["5" "12"]
+         * vlanList = [1 3 5 6 7 8 9 10 11 12]
+         */
+        Set<Short> vlanList = new HashSet<Short>();
+        try {
+            String[] elemArray = dlVlan.split(",");
+            for (String elem : elemArray) {
+                if (elem.contains("-")) {
+                    String[] limits = elem.split("-");
+                    for (short j = Short.valueOf(limits[0]); j <= Short.valueOf(limits[1]); j++) {
+                        vlanList.add(Short.valueOf(j));
+                    }
+                } else {
+                    vlanList.add(Short.valueOf(elem));
+                }
+            }
+        } catch (NumberFormatException e) {
+
+        }
+        return vlanList;
+    }
+
     /**
      * Returns the Source IP Address mask length.
      *
@@ -479,12 +554,12 @@ public class ContainerFlowConfig implements Serializable {
     }
 
     /**
-     * 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);
     }
 
     /**
@@ -519,10 +594,14 @@ public class ContainerFlowConfig implements Serializable {
      * @return true, if is valid
      */
     public Status validate() {
-        if (!hasValidName()) {
+        if (!isValidResourceName(name)) {
             return new Status(StatusCode.BADREQUEST, "Invalid name");
         }
-        Status status = validateIPs();
+        Status status = validateVlan();
+        if (!status.isSuccess()) {
+            return status;
+        }
+        status = validateIPs();
         if (!status.isSuccess()) {
             return status;
         }
@@ -539,12 +618,35 @@ public class ContainerFlowConfig implements Serializable {
     }
 
     /**
-     * Checks if this flow specification configuration has a valid name.
+     * Validates the vlan number
      *
-     * @return true, if successful
+     * @return the result of the check as Status object
      */
-    private boolean hasValidName() {
-        return (name != null && !name.isEmpty() && name.matches(regexName));
+    private Status validateVlan() {
+        if (dlVlan != null) {
+            short vlanId = 0;
+            try {
+                String[] elemArray = dlVlan.split(",");
+                for (String elem : elemArray) {
+                    if (elem.contains("-")) {
+                        String[] limits = elem.split("-");
+                        if (Short.parseShort(limits[0]) < 0
+                                || Short.parseShort(limits[0]) >= Short.parseShort(limits[1])
+                                || Short.parseShort(limits[1]) > 0xfff) {
+                            return new Status(StatusCode.BADREQUEST, "Invalid vlan id");
+                        }
+                    } else {
+                        vlanId = Short.parseShort(elem);
+                        if (vlanId < 0 || vlanId > 0xfff) {
+                            return new Status(StatusCode.BADREQUEST, "Invalid vlan id");
+                        }
+                    }
+                }
+            } catch (NumberFormatException e) {
+                return new Status(StatusCode.BADREQUEST, "Invalid vlan id");
+            }
+        }
+        return new Status(StatusCode.SUCCESS);
     }
 
     /**
@@ -578,16 +680,15 @@ public class ContainerFlowConfig implements Serializable {
 
     /**
      * 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;
     }
 
     /**
@@ -626,18 +727,47 @@ public class ContainerFlowConfig implements Serializable {
 
     /**
      * Returns the matches.
-     * If unidirectional flag is set, there will be only one match in the list
-     * If unidirectional flag is unset there will be two matches in the list,
+     * If unidirectional flag is set, there will be only one match per vlan in the list
+     * If unidirectional flag is unset there will be two matches per vlan in the list,
      * only if the specified flow has an intrinsic direction.
      * For Ex. if the cFlow only has the protocol field configured, no matter
-     * if unidirectional flag is set or not, only one match will be returned
+     * if unidirectional flag is set or not, only one match per vlan will be returned
      * The client just has to iterate over the returned list
      * @return the matches
      */
     public List<Match> getMatches() {
         List<Match> matches = new ArrayList<Match>();
+
+        if (this.dlVlan != null && !this.dlVlan.isEmpty()) {
+            for(Short vlan:getVlanList()){
+                Match match = getMatch(vlan);
+                matches.add(match);
+            }
+        }
+        else{
+            Match match = getMatch(null);
+            matches.add(match);
+        }
+
+        if (!ContainerFlowConfig.unidirectional) {
+            List<Match> forwardMatches = new ArrayList<Match>(matches);
+            for (Match match : forwardMatches) {
+                Match reverse = match.reverse();
+                if (!match.equals(reverse)) {
+                    matches.add(reverse);
+                }
+            }
+        }
+
+        return matches;
+    }
+
+    private Match getMatch(Short vlan){
         Match match = new Match();
 
+        if (vlan != null) {
+            match.setField(MatchType.DL_VLAN, vlan);
+        }
         if (this.nwSrc != null && !this.nwSrc.trim().isEmpty()) {
             String parts[] = this.nwSrc.split("/");
             InetAddress ip = NetUtils.parseInetAddress(parts[0]);
@@ -664,9 +794,8 @@ public class ContainerFlowConfig implements Serializable {
             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());
@@ -674,15 +803,7 @@ public class ContainerFlowConfig implements Serializable {
         if (this.tpDst != null && !this.tpDst.trim().isEmpty()) {
             match.setField(MatchType.TP_DST, Integer.valueOf(tpDst).shortValue());
         }
-
-        matches.add(match);
-        if(!ContainerFlowConfig.unidirectional) {
-            Match reverse = match.reverse();
-            if (!match.equals(reverse)) {
-                matches.add(reverse);
-            }
-        }
-        return matches;
+        return match;
     }
 
     /*
@@ -692,7 +813,7 @@ public class ContainerFlowConfig implements Serializable {
      */
     @Override
     public String toString() {
-        return "Container Flow={name:" + name + " nwSrc:" + nwSrc + " nwDst:" + nwDst + " " + "protocol:" + protocol
+        return "Container Flow={name:" + name + " dlVlan:" + dlVlan + " nwSrc:" + nwSrc + " nwDst:" + nwDst + " " + "protocol:" + protocol
                 + " tpSrc:" + tpSrc + " tpDst:" + tpDst + "}";
     }
 }