Merge "Fixed run.sh to autodetect JAVA_HOME on Mac OS X"
authorAlessandro Boch <aboch@cisco.com>
Sat, 24 Aug 2013 00:20:20 +0000 (00:20 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Sat, 24 Aug 2013 00:20:20 +0000 (00:20 +0000)
opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/Match.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchField.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NetUtils.java
opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java
opendaylight/web/flows/src/main/java/org/opendaylight/controller/flows/web/Flows.java
opendaylight/web/flows/src/main/resources/js/page.js
opendaylight/web/troubleshoot/src/main/java/org/opendaylight/controller/troubleshoot/web/Troubleshoot.java

index de0a3bcd19e990c0287338d0b5e3b1fbe8696c1b..50a87fb568c54ec8e6f6d4e7895c793386d46cf9 100644 (file)
@@ -34,6 +34,9 @@
   </root>
 
   <!--  Base log level  -->
+  <logger name="org.opendaylight" level="INFO"/>
+
+  <!-- Controller log level -->
   <logger name="org.opendaylight.controller" level="INFO"/>
 
   <!-- OSGi logging bridge -->
@@ -69,4 +72,4 @@
   <logger name="audit" level="INFO" additivity="false">
        <appender-ref ref="audit-file"/>
   </logger>
-</configuration>
\ No newline at end of file
+</configuration>
index 9bab8391986df5a82dfc6b3aeeab51155eb84f88..7a94d05bf10990b62a24ebb17d0d16c1f6778ad5 100644 (file)
@@ -246,93 +246,175 @@ public class Match implements Cloneable, Serializable {
     /**
      * Check whether the current match conflicts with the passed filter match
      * This match conflicts with the filter if for at least a MatchType defined
-     * in the filter match, the respective MatchFields differ or are not compatible
+     * in the filter match, the respective MatchFields differ or are not
+     * compatible
+     *
+     * In other words the function returns true if the set of packets described
+     * by one match and the set of packets described by the other match are
+     * disjoint. Equivalently, if the intersection of the two sets of packets
+     * described by the two matches is an empty.
      *
      * For example, Let's suppose the filter has the following MatchFields:
      * DL_TYPE = 0x800
-     * NW_DST =  172.20.30.110/24
+     * NW_DST = 172.20.30.110/24
      *
      * while this match has the following MatchFields:
+     * DL_TYPE = 0x800
      * NW_DST = 172.20.30.45/24
      * TP_DST = 80
      *
-     * Then the function would return false as the two Match are not conflicting
+     * Then the function would return false as the two Match are not
+     * conflicting.
      *
-     * Note: the mask value is taken into account only for MatchType.NW_SRC and MatchType.NW_DST
+     * Note: the mask value is taken into account only for MatchType.NW_SRC and
+     * MatchType.NW_DST
      *
-     * @param match the MAtch describing the filter
-     * @return true if the match is conflicting with the filter, false otherwise
+     * @param match
+     *            the Match describing the filter
+     * @return true if the set of packets described by one match and the set of
+     *         packets described by the other match are disjoint, false
+     *         otherwise
      */
     public boolean conflictWithFilter(Match filter) {
+        return !this.intersetcs(filter);
+    }
+
+    /**
+     * Merge the current Match fields with the fields of the filter Match. A
+     * check is first run to see if this Match is compatible with the filter
+     * Match. If it is not, the merge is not attempted.
+     *
+     * The result is the match object representing the intersection of the set
+     * of packets described by this match with the set of packets described by
+     * the filter match. If the intersection of the two sets is empty, the
+     * return match will be empty as well.
+     *
+     * @param filter
+     *            the match with which attempting the merge
+     * @return a new Match object describing the set of packets represented by
+     *         the intersection of this and the filter matches.
+     */
+    public Match mergeWithFilter(Match filter) {
+        return this.getIntersection(filter);
+    }
+
+    /**
+     * Return the match representing the intersection of the set of packets
+     * described by this match with the set of packets described by the other
+     * match. Such as m.intersect(m) == m and m.intersect(o) == o where o is an
+     * empty match.
+     *
+     * @param other
+     *            the match with which computing the intersection
+     * @return a new Match object representing the intersection of the set of
+     *         packets described by this match with the set of packets described
+     *         by the other match.
+     */
+    public Match getIntersection(Match other) {
+        Match intersection = new Match();
+        if (this.intersetcs(other)) {
+            for (MatchType type : MatchType.values()) {
+                if (this.isAny(type) && other.isAny(type)) {
+                    continue;
+                }
+                if (this.isAny(type)) {
+                    intersection.setField(other.getField(type).clone());
+                    continue;
+                } else if (other.isAny(type)) {
+                    intersection.setField(this.getField(type).clone());
+                    continue;
+                }
+                // Either they are equal or it is about IP address
+                switch (type) {
+                // When it is about IP address, take the wider prefix address between the twos
+                case NW_SRC:
+                case NW_DST:
+                    MatchField thisField = this.getField(type);
+                    MatchField otherField = other.getField(type);
+                    InetAddress thisAddress = (InetAddress) thisField.getValue();
+                    InetAddress otherAddress = (InetAddress) otherField.getValue();
+                    InetAddress thisMask = (InetAddress) thisField.getMask();
+                    InetAddress otherMask = (InetAddress) otherField.getMask();
+
+                    int thisMaskLen = (thisMask == null) ? ((thisAddress instanceof Inet4Address) ? 32 : 128)
+                            : NetUtils.getSubnetMaskLength(thisMask);
+                    int otherMaskLen = (otherMask == null) ? ((otherAddress instanceof Inet4Address) ? 32 : 128)
+                            : NetUtils.getSubnetMaskLength(otherMask);
+                    if (otherMaskLen < thisMaskLen) {
+                        intersection.setField(new MatchField(type, NetUtils.getSubnetPrefix(otherAddress, otherMaskLen), otherMask));
+                    } else {
+                        intersection.setField(new MatchField(type, NetUtils.getSubnetPrefix(thisAddress, thisMaskLen), thisMask));
+                    }
+                    break;
+                default:
+                    // this and other match field are equal for this type, pick this match field
+                    intersection.setField(this.getField(type).clone());
+                }
+            }
+        }
+        return intersection;
+    }
+
+    /**
+     * Checks whether the intersection of the set of packets described by this
+     * match with the set of packets described by the other match is non empty
+     *
+     * For example, if this match is: DL_SRC = 00:cc:bb:aa:11:22
+     *
+     * and the other match is: DL_TYPE = 0x800 NW_SRC = 1.2.3.4
+     *
+     * then their respective matching packets set intersection is non empty:
+     * DL_SRC = 00:cc:bb:aa:11:22 DL_TYPE = 0x800 NW_SRC = 1.2.3.4
+     *
+     * @param other
+     *            the other match with which testing the intersection
+     * @return true if the intersection of the respective matching packets sets
+     *         is non empty
+     */
+    public boolean intersetcs(Match other) {
+        if (this.getMatches() == 0 || other.getMatches() == 0) {
+            // No intersection with the empty set
+            return false;
+        }
         // Iterate through the MatchType defined in the filter
-        for (MatchType type : filter.getMatchesList()) {
-            if (this.isAny(type)) {
+        for (MatchType type : MatchType.values()) {
+            if (this.isAny(type) || other.isAny(type)) {
                 continue;
             }
 
             MatchField thisField = this.getField(type);
-            MatchField filterField = filter.getField(type);
+            MatchField otherField = other.getField(type);
 
             switch (type) {
             case DL_SRC:
             case DL_DST:
-                if (Arrays.equals((byte[]) thisField.getValue(),
-                        (byte[]) filterField.getValue())) {
+                if (!Arrays.equals((byte[]) thisField.getValue(), (byte[]) otherField.getValue())) {
                     return false;
                 }
                 break;
             case NW_SRC:
             case NW_DST:
                 InetAddress thisAddress = (InetAddress) thisField.getValue();
-                InetAddress filterAddress = (InetAddress) filterField
-                        .getValue();
+                InetAddress otherAddress = (InetAddress) otherField.getValue();
                 // Validity check
-                if (thisAddress instanceof Inet4Address
-                        && filterAddress instanceof Inet6Address
-                        || thisAddress instanceof Inet6Address
-                        && filterAddress instanceof Inet4Address) {
-                    return true;
+                if (thisAddress instanceof Inet4Address && otherAddress instanceof Inet6Address
+                        || thisAddress instanceof Inet6Address && otherAddress instanceof Inet4Address) {
+                    return false;
                 }
                 InetAddress thisMask = (InetAddress) thisField.getMask();
-                InetAddress filterMask = (InetAddress) filterField.getMask();
-                // thisAddress has to be in same subnet of filterAddress
-                if (NetUtils.inetAddressConflict(thisAddress, filterAddress,
-                        thisMask, filterMask)) {
-                    return true;
+                InetAddress otherMask = (InetAddress) otherField.getMask();
+                if (NetUtils.inetAddressConflict(thisAddress, otherAddress, thisMask, otherMask)
+                        && NetUtils.inetAddressConflict(otherAddress, thisAddress, otherMask, thisMask)) {
+                    return false;
                 }
                 break;
             default:
-                if (!thisField.getValue().equals(filterField.getValue())) {
-                    return true;
-                }
-            }
-            //TODO: check v4 v6 incompatibility
-        }
-        return false;
-    }
-
-    /**
-     * Merge the current Match fields with the fields of the filter Match
-     * A check is first run to see if this Match is compatible with the
-     * filter Match. If it is not, the merge is not attempted.
-     *
-     *
-     * @param filter
-     * @return
-     */
-    public Match mergeWithFilter(Match filter) {
-        if (!this.conflictWithFilter(filter)) {
-            /*
-             * No conflict with the filter
-             * We can copy over the fields which this match does not have
-             */
-            for (MatchType type : filter.getMatchesList()) {
-                if (this.isAny(type)) {
-                    this.setField(filter.getField(type).clone());
+                if (!thisField.getValue().equals(otherField.getValue())) {
+                    return false;
                 }
             }
         }
-        return this;
+        return true;
     }
 
     @Override
index 3b8a2952164eafb0cf463208d06cc29a182e2d6f..54be4c67189412a208dc5cfebb6fef2ff49f0301 100644 (file)
@@ -184,7 +184,8 @@ public class MatchField implements Cloneable, Serializable {
 
     @Override
     public String toString() {
-        return type + "(" + getValueString() + "," + getMaskString() + ")";
+        return (mask == null) ? String.format("%s(%s)", getTypeString(), getValueString()) :
+            String.format("%s(%s,%s)", getTypeString(), getValueString(), getMaskString());
     }
 
     @Override
index 0fce4f4b0aea447a26c2884a1d6b6b3814ba9df5..e94021119d14f11e7581d5e68b6e096921a07725 100644 (file)
@@ -247,11 +247,18 @@ public abstract class NetUtils {
      * Checks if the test address and mask conflicts with the filter address and
      * mask
      *
-     * For example: testAddress: 172.28.2.23 testMask: 255.255.255.0
-     * filtAddress: 172.28.1.10 testMask: 255.255.255.0 conflict
+     * For example:
+     * testAddress: 172.28.2.23
+     * testMask: 255.255.255.0
+     * filterAddress: 172.28.1.10
+     * testMask: 255.255.255.0
+     * do conflict
      *
-     * testAddress: 172.28.2.23 testMask: 255.255.255.0 filtAddress: 172.28.1.10
-     * testMask: 255.255.0.0 do not conflict
+     * testAddress: 172.28.2.23
+     * testMask: 255.255.255.0
+     * filterAddress: 172.28.1.10
+     * testMask: 255.255.0.0
+     * do not conflict
      *
      * Null parameters are permitted
      *
@@ -275,7 +282,8 @@ public abstract class NetUtils {
 
         int testMaskLen = (testMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
                 .getSubnetMaskLength(testMask);
-        int filterMaskLen = NetUtils.getSubnetMaskLength(filterMask);
+        int filterMaskLen = (filterMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
+                .getSubnetMaskLength(filterMask);
 
         // Mask length check. Test mask has to be more specific than filter one
         if (testMaskLen < filterMaskLen) {
@@ -464,7 +472,7 @@ public abstract class NetUtils {
 
     /*
      * Following utilities are useful when you need to compare or bit shift java
-     * primitive type variable which are inerently signed
+     * primitive type variable which are inherently signed
      */
     /**
      * Returns the unsigned value of the passed byte variable
index ae78e1acc8af45f8ef879b0ad16477bf9040330a..5dcb898dfbb9db5e4420e0cafa06b8977979d8af 100644 (file)
@@ -523,4 +523,94 @@ public class MatchTest {
         Assert.assertTrue(field.getValue().equals(new Short(vlan)));
         Assert.assertTrue(field.isValid());
     }
+
+    @Test
+    public void testIntersection() throws UnknownHostException {
+        Short ethType = Short.valueOf((short)0x800);
+        InetAddress ip1 = InetAddress.getByName("1.1.1.1");
+        InetAddress ip2 = InetAddress.getByName("1.1.1.0");
+        InetAddress ipm2 = InetAddress.getByName("255.255.255.0");
+        InetAddress ip3 = InetAddress.getByName("1.3.0.0");
+        InetAddress ipm3 = InetAddress.getByName("255.255.0.0");
+
+        Match m1 = new Match();
+        m1.setField(MatchType.DL_TYPE, ethType);
+        m1.setField(MatchType.NW_SRC, ip1);
+
+        Match m2 = new Match();
+        m2.setField(MatchType.DL_TYPE, ethType);
+        m2.setField(MatchType.NW_SRC, ip2, ipm2);
+
+        Match m3 = new Match();
+        m3.setField(MatchType.DL_TYPE, ethType);
+        m3.setField(MatchType.NW_SRC, ip3, ipm3);
+        m3.setField(MatchType.NW_PROTO, IPProtocols.TCP.byteValue());
+
+        Match m3r = m3.reverse();
+        Assert.assertTrue(m3.intersetcs(m3r));
+
+        Assert.assertTrue(m1.intersetcs(m2));
+        Assert.assertTrue(m2.intersetcs(m1));
+        Assert.assertFalse(m1.intersetcs(m3));
+        Assert.assertTrue(m1.intersetcs(m3r));
+        Assert.assertFalse(m3.intersetcs(m1));
+        Assert.assertTrue(m3.intersetcs(m1.reverse()));
+        Assert.assertFalse(m2.intersetcs(m3));
+        Assert.assertFalse(m3.intersetcs(m2));
+        Assert.assertTrue(m2.intersetcs(m3r));
+
+
+        Match i = m1.getIntersection(m2);
+        Assert.assertTrue(((Short)i.getField(MatchType.DL_TYPE).getValue()).equals(ethType));
+        Assert.assertTrue(((InetAddress)i.getField(MatchType.NW_SRC).getValue()).equals(ip2));
+        Assert.assertTrue(((InetAddress)i.getField(MatchType.NW_SRC).getMask()).equals(ipm2));
+
+        i = m2.getIntersection(m3);
+        Assert.assertTrue(i.getMatches() == 0);
+
+        Match m4 = new Match();
+        m4.setField(MatchType.DL_TYPE, ethType);
+        m4.setField(MatchType.NW_PROTO, IPProtocols.TCP.byteValue());
+        Assert.assertTrue(m4.intersetcs(m3));
+
+        Match m5 = new Match();
+        m5.setField(MatchType.DL_TYPE, ethType);
+        m3.setField(MatchType.NW_SRC, ip3, ipm3);
+        m5.setField(MatchType.NW_PROTO, IPProtocols.UDP.byteValue());
+        Assert.assertFalse(m5.intersetcs(m3));
+        Assert.assertFalse(m5.intersetcs(m4));
+        Assert.assertTrue(m5.intersetcs(m5));
+        Assert.assertFalse(m3.intersetcs(m5));
+        Assert.assertFalse(m4.intersetcs(m5));
+
+
+        Match i2 = m4.getIntersection(m3);
+        Assert.assertFalse(i2.getMatches() == 0);
+        Assert.assertFalse(i2.getMatchesList().isEmpty());
+        Assert.assertTrue(((InetAddress)i2.getField(MatchType.NW_SRC).getValue()).equals(ip3));
+        Assert.assertTrue(((InetAddress)i2.getField(MatchType.NW_SRC).getMask()).equals(ipm3));
+        Assert.assertTrue(((Byte)i2.getField(MatchType.NW_PROTO).getValue()).equals(IPProtocols.TCP.byteValue()));
+
+        byte src[] = {(byte)0, (byte)0xab,(byte)0xbc,(byte)0xcd,(byte)0xde,(byte)0xef};
+        byte dst[] = {(byte)0x10, (byte)0x11,(byte)0x12,(byte)0x13,(byte)0x14,(byte)0x15};
+        Short srcPort = (short)1024;
+        Short dstPort = (short)80;
+
+        // Check identity
+        Match m6 = new Match();
+        m6.setField(MatchType.DL_SRC, src);
+        m6.setField(MatchType.DL_DST, dst);
+        m6.setField(MatchType.NW_SRC, ip2, ipm2);
+        m6.setField(MatchType.NW_DST, ip3, ipm3);
+        m6.setField(MatchType.NW_PROTO, IPProtocols.UDP.byteValue());
+        m6.setField(MatchType.TP_SRC, srcPort);
+        m6.setField(MatchType.TP_DST, dstPort);
+        Assert.assertTrue(m6.intersetcs(m6));
+        Assert.assertTrue(m6.getIntersection(m6).equals(m6));
+
+        // Empty match, represents the empty set
+        Match o = new Match();
+        Assert.assertTrue(m6.getIntersection(o).equals(o));
+        Assert.assertTrue(o.getIntersection(m6).equals(o));
+    }
 }
index 9444360eecb7d7ae4a6e084a4fde8512c7b5ed71..a96d3efcec698d80a243969fd2c1c3df9ee1e2cf 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.controller.flows.web;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -77,13 +78,16 @@ public class Flows implements IDaylightWeb {
 
     @RequestMapping(value = "/main")
     @ResponseBody
-    public Map<String, Object> getFlows(HttpServletRequest request, @RequestParam(required = false) String container) {
-        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+    public Map<String, Object> getFlows(HttpServletRequest request,
+            @RequestParam(required = false) String container) {
+        String containerName = (container == null) ? GlobalConstants.DEFAULT
+                .toString() : container;
 
         // Derive the privilege this user has on the current container
         String userName = request.getUserPrincipal().getName();
-        Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
-        if (privilege  == Privilege.NONE) {
+        Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName,
+                containerName, this);
+        if (privilege == Privilege.NONE) {
             return null;
         }
 
@@ -114,7 +118,7 @@ public class Flows implements IDaylightWeb {
             flowSet.add(entry);
         }
 
-        Map <String, Object> output = new HashMap<String, Object>(2);
+        Map<String, Object> output = new HashMap<String, Object>(2);
         output.put("flows", flowSet);
         output.put("privilege", privilege);
         return output;
@@ -122,12 +126,15 @@ public class Flows implements IDaylightWeb {
 
     @RequestMapping(value = "/node-ports")
     @ResponseBody
-    public Map<String, Object> getNodePorts(HttpServletRequest request, @RequestParam(required = false) String container) {
-        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+    public Map<String, Object> getNodePorts(HttpServletRequest request,
+            @RequestParam(required = false) String container) {
+        String containerName = (container == null) ? GlobalConstants.DEFAULT
+                .toString() : container;
 
         // Derive the privilege this user has on the current container
         String userName = request.getUserPrincipal().getName();
-        if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) == Privilege.NONE) {
+        if (DaylightWebUtil
+                .getContainerPrivilege(userName, containerName, this) == Privilege.NONE) {
             return null;
         }
 
@@ -171,12 +178,15 @@ public class Flows implements IDaylightWeb {
 
     @RequestMapping(value = "/node-flows")
     @ResponseBody
-    public Map<String, Object> getNodeFlows(HttpServletRequest request, @RequestParam(required = false) String container) {
-        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+    public Map<String, Object> getNodeFlows(HttpServletRequest request,
+            @RequestParam(required = false) String container) {
+        String containerName = (container == null) ? GlobalConstants.DEFAULT
+                .toString() : container;
 
         // Derive the privilege this user has on the current container
         String userName = request.getUserPrincipal().getName();
-        if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) == Privilege.NONE) {
+        if (DaylightWebUtil
+                .getContainerPrivilege(userName, containerName, this) == Privilege.NONE) {
             return null;
         }
 
@@ -199,10 +209,12 @@ public class Flows implements IDaylightWeb {
             List<FlowConfig> flows = frm.getStaticFlows(node);
 
             String nodeDesc = node.toString();
-            SwitchConfig config = switchManager.getSwitchConfig(node
-                    .toString());
-            if ((config != null) && (config.getProperty(Description.propertyName) != null)) {
-                nodeDesc = ((Description) config.getProperty(Description.propertyName)).getValue();
+            SwitchConfig config = switchManager
+                    .getSwitchConfig(node.toString());
+            if ((config != null)
+                    && (config.getProperty(Description.propertyName) != null)) {
+                nodeDesc = ((Description) config
+                        .getProperty(Description.propertyName)).getValue();
             }
 
             nodes.put(nodeDesc, flows.size());
@@ -216,12 +228,15 @@ public class Flows implements IDaylightWeb {
     public String actionFlow(@RequestParam(required = true) String action,
             @RequestParam(required = false) String body,
             @RequestParam(required = true) String nodeId,
-            HttpServletRequest request, @RequestParam(required = false) String container) {
-        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+            HttpServletRequest request,
+            @RequestParam(required = false) String container) {
+        String containerName = (container == null) ? GlobalConstants.DEFAULT
+                .toString() : container;
 
         // Authorization check
         String userName = request.getUserPrincipal().getName();
-        if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
+        if (DaylightWebUtil
+                .getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
             return "Operation not authorized";
         }
 
@@ -238,7 +253,8 @@ public class Flows implements IDaylightWeb {
         Status result = new Status(StatusCode.BADREQUEST, "Invalid request");
         if (action.equals("add")) {
             result = frm.addStaticFlow(flow);
-            DaylightWebUtil.auditlog("Flow", userName, "added", flow.getName(), containerName);
+            DaylightWebUtil.auditlog("Flow", userName, "added", flow.getName(),
+                    containerName);
         }
 
         return (result.isSuccess()) ? StatusCode.SUCCESS.toString() : result
@@ -250,12 +266,15 @@ public class Flows implements IDaylightWeb {
     public String removeFlow(@PathVariable("nodeId") String nodeId,
             @PathVariable("name") String name,
             @RequestParam(required = true) String action,
-            HttpServletRequest request, @RequestParam(required = false) String container) {
-        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+            HttpServletRequest request,
+            @RequestParam(required = false) String container) {
+        String containerName = (container == null) ? GlobalConstants.DEFAULT
+                .toString() : container;
 
         // Authorization check
         String userName = request.getUserPrincipal().getName();
-        if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
+        if (DaylightWebUtil
+                .getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
             return "Operation not authorized";
         }
 
@@ -272,13 +291,15 @@ public class Flows implements IDaylightWeb {
         }
         if (action.equals("remove")) {
             result = frm.removeStaticFlow(name, node);
-            if(result.isSuccess()) {
-                DaylightWebUtil.auditlog("Flow", userName, "removed", name, containerName);
+            if (result.isSuccess()) {
+                DaylightWebUtil.auditlog("Flow", userName, "removed", name,
+                        containerName);
             }
         } else if (action.equals("toggle")) {
             result = frm.toggleStaticFlowStatus(name, node);
-            if(result.isSuccess()) {
-                DaylightWebUtil.auditlog("Flow", userName, "toggled", name, containerName);
+            if (result.isSuccess()) {
+                DaylightWebUtil.auditlog("Flow", userName, "toggled", name,
+                        containerName);
             }
         } else {
             result = new Status(StatusCode.BADREQUEST, "Unknown action");
@@ -288,10 +309,58 @@ public class Flows implements IDaylightWeb {
                 .getDescription();
     }
 
+    @SuppressWarnings("unchecked")
+    @RequestMapping(value = "/flow/deleteFlows", method = RequestMethod.POST)
+    @ResponseBody
+    public String removeSelectedFlows(
+            @RequestParam(required = false) String body,
+            HttpServletRequest request,
+            @RequestParam(required = false) String container) {
+        String containerName = (container == null) ? GlobalConstants.DEFAULT
+                .toString() : container;
+
+        // Authorization check
+        String userName = request.getUserPrincipal().getName();
+        if (DaylightWebUtil
+                .getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
+            return "Operation not authorized";
+        }
+
+        IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper
+                .getInstance(IForwardingRulesManager.class, containerName, this);
+        if (frm == null) {
+            return "Forwarding Rules Manager is not available";
+        }
+
+        Gson gson = new Gson();
+        List<Map<String, String>> flowList = new ArrayList<Map<String, String>>();
+        flowList = gson.fromJson(body, flowList.getClass());
+        Status result = new Status(StatusCode.BADREQUEST, "Invalid request");
+        String status = "";
+        for (Map<String, String> flowEntry : flowList) {
+            Node node = Node.fromString(flowEntry.get("node"));
+            result = frm.removeStaticFlow(flowEntry.get("name"), node);
+            if (result.isSuccess()) {
+                DaylightWebUtil.auditlog("Flow", userName, "removed",
+                        flowEntry.get("name"), containerName);
+            } else {
+                status = flowEntry.get("name") + ", " + status;
+            }
+        }
+        if (!status.equals("")) {
+            return "Could not remove "
+                    + status.substring(0, status.length() - 2) + " Flow(s)";
+        } else {
+            return "Success";
+        }
+    }
+
     private String getNodeDesc(Node node, ISwitchManager switchManager) {
-        Description desc = (Description) switchManager.getNodeProp(node, Description.propertyName);
+        Description desc = (Description) switchManager.getNodeProp(node,
+                Description.propertyName);
         String description = (desc == null) ? "" : desc.getValue();
-        return (description.isEmpty() || description.equalsIgnoreCase("none")) ? node.toString() : description;
+        return (description.isEmpty() || description.equalsIgnoreCase("none")) ? node
+                .toString() : description;
     }
 
 }
index 0f1eabb85929dde53cecacf939b69c4b1e651edb..3dcf9e3006914daa3824476bf25ec1667024d455 100644 (file)
@@ -48,7 +48,8 @@ one.f.address = {
         main : "/main",
         flows : "/node-flows",
         nodes : "/node-ports",
-        flow : "/flow"
+        flow : "/flow",
+        deleteFlows:"/flow/deleteFlows"
     }
 }
 
@@ -251,9 +252,11 @@ one.f.flows = {
     id : {
         dashlet : {
             add : "one_f_flows_id_dashlet_add",
+            removeMultiple : "one_f_flows_id_dashlet_removeMultiple",
             remove : "one_f_flows_id_dashlet_remove",
             toggle : "one_f_flows_id_dashlet_toggle",
-            datagrid: "one_f_flows_id_dashlet_datagrid"
+            datagrid : "one_f_flows_id_dashlet_datagrid",
+            selectAllFlows : "one_f_flows_id_dashlet_selectAllFlows"
         },
         modal : {
             install : "one_f_flows_id_modal_install",
@@ -327,6 +330,36 @@ one.f.flows = {
                     $modal.modal();
                 });
                 $dashlet.append($button);
+                var button = one.lib.dashlet.button.single("Remove Flow Entry", one.f.flows.id.dashlet.removeMultiple, "btn-primary", "btn-mini");
+                var $button = one.lib.dashlet.button.button(button);
+
+                $button.click(function() {
+                    var checkedCheckBoxes = $('.flowEntry[type=checkbox]:checked');
+                    
+                    var requestData = [];
+                    
+                    var resource = {};
+                    checkedCheckBoxes.each(function(index, value) {
+                        var flowEntry = {};
+                        flowEntry['name'] = checkedCheckBoxes[index].name;
+                        flowEntry['node'] = checkedCheckBoxes[index].getAttribute("node");
+                        requestData.push(flowEntry);  
+                    });
+                    resource['body'] = JSON.stringify(requestData);
+
+                    $.post(one.f.address.root+one.f.address.flows.deleteFlows, resource, function(response) {
+                        if(response == "Success") {
+                            one.lib.alert("Flow(s) successfully removed");                            
+                        } else {
+                            one.lib.alert(response);
+                        }
+                        one.main.dashlet.right.bottom.empty();
+                        one.f.detail.dashlet(one.main.dashlet.right.bottom);
+                        one.main.dashlet.left.top.empty();
+                        one.f.flows.dashlet(one.main.dashlet.left.top);
+                    });                    
+                });
+                $dashlet.append($button);
 
             }
 
@@ -339,7 +372,12 @@ one.f.flows = {
             $dashlet.append($gridHTML);
             var dataSource = one.f.flows.data.flowsDataGrid(data);
             $("#" + one.f.flows.id.dashlet.datagrid).datagrid({dataSource: dataSource}).on("loaded", function() {
-                $("#" + one.f.flows.id.dashlet.datagrid).find("tbody tr").each(function(index, tr) {
+                    $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows).click(function() {
+                                $("#" + one.f.flows.id.dashlet.datagrid).find(':checkbox').prop('checked',
+                                        $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows).is(':checked'));
+                    });
+                    
+                    $("#" + one.f.flows.id.dashlet.datagrid).find("tbody tr").each(function(index, tr) {
                     $tr = $(tr);
                     $span = $("td span", $tr);
                     var flowstatus = $span.data("flowstatus");
@@ -357,10 +395,22 @@ one.f.flows = {
                     });
                     // attach click event
                     $tr.click(function() {
-                        var $td = $($(this).find("td")[0]);
+                        var $td = $($(this).find("td")[1]);
                         var id = $td.text();
                         var node = $td.find("span").data("nodeid");
-                        one.f.flows.detail(id, node);   
+                        one.f.flows.detail(id, node);
+                    });
+                    $(".flowEntry").click(function(){
+                                if (!$('.flowEntry[type=checkbox]:not(:checked)').length) {
+                            $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows)
+                                .prop("checked",
+                              true);
+                        } else {
+                            $("#"+one.f.flows.id.dashlet.datagrid.selectAllFlows)
+                                .prop("checked",
+                             false);
+                        }
+                        event.stopPropagation();
                     });
                 });
             });
@@ -1193,6 +1243,11 @@ one.f.flows = {
         flowsDataGrid: function(data) {
             var source = new StaticDataSource({
                     columns: [
+                        {
+                            property: 'selector',
+                            label: "<input type='checkbox' id='"+one.f.flows.id.dashlet.datagrid.selectAllFlows+"'/>",
+                            sortable: false
+                        },
                         {
                             property: 'name',
                             label: 'Flow Name',
@@ -1207,7 +1262,13 @@ one.f.flows = {
                     data: data.flows,
                     formatter: function(items) {
                         $.each(items, function(index, item) {
-                            item["name"] = '<span data-installInHw=' + item["flow"]["installInHw"] + 
+                                    var $checkbox = document.createElement("input");
+                            $checkbox.setAttribute("type", "checkbox");
+                            $checkbox.setAttribute("name", item.name);
+                            $checkbox.setAttribute("node", item.node);
+                            $checkbox.setAttribute('class','flowEntry')
+                            item.selector = $checkbox.outerHTML;
+                                  item["name"] = '<span data-installInHw=' + item["flow"]["installInHw"] + 
                                 ' data-flowstatus=' + item["flow"]["status"] + 
                                 ' data-nodeId=' + item["nodeId"] + '>' + item["name"] + '</span>';
                         });
@@ -1222,6 +1283,8 @@ one.f.flows = {
             $(data).each(function(index, value) {
                 var tr = {};
                 var entry = [];
+
+                
                 entry.push(value['name']);
                 entry.push(value['node']);
                 if (value['flow']['installInHw'] == 'true' && value['flow']['status'] == 'Success')
@@ -1244,12 +1307,12 @@ one.f.flows = {
             var $table = one.lib.dashlet.table.table(attributes);
 
             var headers = ['Flow Name', 'Node'];
+                
             var $thead = one.lib.dashlet.table.header(headers);
             $table.append($thead);
 
             var $tbody = one.lib.dashlet.table.body(body);
             $table.append($tbody);
-
             return $table;
         }
     }
index 337d721696b8003713fe3805563c091760d1852b..71ba687f2d4b16e22c43de7586f6d75c7119b7ac 100644 (file)
@@ -208,7 +208,7 @@ public class Troubleshoot implements IDaylightWeb {
                 List<NodeConnectorStatistics> statistics = statisticsManager
                         .getNodeConnectorStatistics(node);
                 for (NodeConnectorStatistics stats : statistics) {
-                    cells.add(this.convertPortsStatistics(stats));
+                    cells.add(this.convertPortsStatistics(stats, containerName));
                 }
             }
         }
@@ -220,11 +220,19 @@ public class Troubleshoot implements IDaylightWeb {
     }
 
     private Map<String, String> convertPortsStatistics(
-            NodeConnectorStatistics ncStats) {
+            NodeConnectorStatistics ncStats, String containerName) {
         Map<String, String> row = new HashMap<String, String>();
 
+        ISwitchManager switchManager = (ISwitchManager) ServiceHelper
+                .getInstance(ISwitchManager.class, containerName, this);
+        NodeConnector nodeConnector = ncStats.getNodeConnector();
+        Description description = (Description) switchManager.getNodeProp(nodeConnector.getNode(), Description.propertyName);
+        String desc = (description == null) ? "" : description.getValue();
+        String nodeName = desc.equalsIgnoreCase("none") ? nodeConnector.getNode().getNodeIDString() : desc;
+        String nodeConnectorDisplayName = nodeConnector.getType() + "|" + nodeConnector.getID() + "@" + nodeName;
         row.put("nodeConnector",
-                String.valueOf(ncStats.getNodeConnector().toString()));
+                String.valueOf(nodeConnectorDisplayName));
+
         row.put("rxPkts", String.valueOf(ncStats.getReceivePacketCount()));
         row.put("txPkts", String.valueOf(ncStats.getTransmitPacketCount()));
         row.put("rxBytes", String.valueOf(ncStats.getReceiveByteCount()));