Relax conflict check in FRM
[controller.git] / opendaylight / forwardingrulesmanager / implementation / src / main / java / org / opendaylight / controller / forwardingrulesmanager / internal / ForwardingRulesManager.java
index 45973fe167356b470b97f6bc7d287f59af769d31..bbc6048d8465f86f2678bc72861895a224d14955 100644 (file)
@@ -106,11 +106,12 @@ public class ForwardingRulesManager implements
         ICacheUpdateAware<Object,Object>,
         CommandProvider,
         IFlowProgrammerListener {
-    private static final String NODEDOWN = "Node is Down";
-    private static final String SUCCESS = StatusCode.SUCCESS.toString();
+
     private static final Logger log = LoggerFactory.getLogger(ForwardingRulesManager.class);
-    private static final String PORTREMOVED = "Port removed";
     private static final Logger logsync = LoggerFactory.getLogger("FRMsync");
+    private static final String PORTREMOVED = "Port removed";
+    private static final String NODEDOWN = "Node is Down";
+    private static final String INVALID_FLOW_ENTRY = "Invalid FlowEntry";
     private String frmFileName;
     private String portGroupFileName;
     private ConcurrentMap<Integer, FlowConfig> staticFlows;
@@ -164,8 +165,8 @@ public class ForwardingRulesManager implements
      * necessity non-transactional as long as need to be able to synchronize
      * states also while a transaction is in progress
      */
-    static final String WORKORDERCACHE = "frm.workOrder";
-    static final String WORKSTATUSCACHE = "frm.workStatus";
+    static final String WORK_ORDER_CACHE = "frm.workOrder";
+    static final String WORK_STATUS_CACHE = "frm.workStatus";
 
     /*
      * Data structure responsible for distributing the FlowEntryInstall requests
@@ -268,11 +269,34 @@ public class ForwardingRulesManager implements
     private Status addEntry(FlowEntry flowEntry, boolean async) {
 
         // Sanity Check
-        if (flowEntry == null || flowEntry.getNode() == null) {
-            String msg = "Invalid FlowEntry";
-            String logMsg = msg + ": {}";
+        if (flowEntry == null || flowEntry.getNode() == null || flowEntry.getFlow() == null) {
+            String logMsg = INVALID_FLOW_ENTRY + ": {}";
             log.warn(logMsg, flowEntry);
-            return new Status(StatusCode.NOTACCEPTABLE, msg);
+            return new Status(StatusCode.NOTACCEPTABLE, INVALID_FLOW_ENTRY);
+        }
+
+        /*
+         * Redundant Check: Check if the request is a redundant one from the
+         * same application the flowEntry is equal to an existing one. Given we
+         * do not have an application signature in the requested FlowEntry yet,
+         * we are here detecting the above condition by comparing the flow
+         * names, if set. If they are equal to the installed flow, most likely
+         * this is a redundant installation request from the same application
+         * and we can silently return success
+         *
+         * TODO: in future a sort of application reference list mechanism will
+         * be added to the FlowEntry so that exact flow can be used by different
+         * applications.
+         */
+        FlowEntry present = this.originalSwView.get(flowEntry);
+        if (present != null) {
+            boolean sameFlow = present.getFlow().equals(flowEntry.getFlow());
+            boolean sameApp = present.getFlowName() != null && present.getFlowName().equals(flowEntry.getFlowName());
+            if (sameFlow && sameApp) {
+                log.trace("Skipping redundant request for flow {} on node {}", flowEntry.getFlowName(),
+                        flowEntry.getNode());
+                return new Status(StatusCode.SUCCESS, "Entry is already present");
+            }
         }
 
         /*
@@ -331,7 +355,7 @@ public class ForwardingRulesManager implements
                 succeded = ret;
             } else {
                 error = ret;
-                log.warn("Failed to install the entry: {}. The failure is: {}", installEntry, ret.getDescription());
+                log.trace("Failed to install the entry: {}. The failure is: {}", installEntry, ret.getDescription());
             }
         }
 
@@ -387,8 +411,8 @@ public class ForwardingRulesManager implements
 
         // Sanity checks
         if (currentFlowEntry == null || currentFlowEntry.getNode() == null || newFlowEntry == null
-                || newFlowEntry.getNode() == null) {
-            String msg = "Modify: Invalid FlowEntry";
+                || newFlowEntry.getNode() == null || newFlowEntry.getFlow() == null) {
+            String msg = "Modify: " + INVALID_FLOW_ENTRY;
             String logMsg = msg + ": {} or {}";
             log.warn(logMsg, currentFlowEntry, newFlowEntry);
             return new Status(StatusCode.NOTACCEPTABLE, msg);
@@ -577,7 +601,7 @@ public class ForwardingRulesManager implements
                     .getFlow());
 
             if (!status.isSuccess()) {
-                log.warn("SDN Plugin failed to program the flow: {}. The failure is: {}", newEntries.getInstall(),
+                log.trace("SDN Plugin failed to program the flow: {}. The failure is: {}", newEntries.getInstall(),
                         status.getDescription());
                 return status;
             }
@@ -608,11 +632,10 @@ public class ForwardingRulesManager implements
         Status error = new Status(null, null);
 
         // Sanity Check
-        if (flowEntry == null || flowEntry.getNode() == null) {
-            String msg = "Invalid FlowEntry";
-            String logMsg = msg + ": {}";
+        if (flowEntry == null || flowEntry.getNode() == null || flowEntry.getFlow() == null) {
+            String logMsg = INVALID_FLOW_ENTRY + ": {}";
             log.warn(logMsg, flowEntry);
-            return new Status(StatusCode.NOTACCEPTABLE, msg);
+            return new Status(StatusCode.NOTACCEPTABLE, INVALID_FLOW_ENTRY);
         }
 
         // Derive the container flows merged installed entries
@@ -637,7 +660,7 @@ public class ForwardingRulesManager implements
 
             if (!ret.isSuccess()) {
                 error = ret;
-                log.warn("Failed to remove the entry: {}. The failure is: {}", entry.getInstall(), ret.getDescription());
+                log.trace("Failed to remove the entry: {}. The failure is: {}", entry.getInstall(), ret.getDescription());
                 if (installedList.size() == 1) {
                     // If we had only one entry to remove, this is fatal failure
                     return error;
@@ -695,7 +718,7 @@ public class ForwardingRulesManager implements
                     .getFlow());
 
             if (!status.isSuccess()) {
-                log.warn("SDN Plugin failed to program the flow: {}. The failure is: {}", entry.getInstall(),
+                log.trace("SDN Plugin failed to remove the flow: {}. The failure is: {}", entry.getInstall(),
                         status.getDescription());
                 return status;
             }
@@ -745,7 +768,7 @@ public class ForwardingRulesManager implements
                     .getFlow());
 
             if (!status.isSuccess()) {
-                log.warn("SDN Plugin failed to program the flow: {}. The failure is: {}", entry.getInstall(),
+                log.trace("SDN Plugin failed to program the flow: {}. The failure is: {}", entry.getInstall(),
                         status.getDescription());
                 return status;
             }
@@ -915,7 +938,7 @@ public class ForwardingRulesManager implements
             updateLocalDatabase(target, false);
         } else {
             // log the error
-            log.warn("SDN Plugin failed to remove the flow: {}. The failure is: {}", target.getInstall(),
+            log.trace("SDN Plugin failed to remove the flow: {}. The failure is: {}", target.getInstall(),
                     status.getDescription());
         }
 
@@ -1385,10 +1408,10 @@ public class ForwardingRulesManager implements
             clusterContainerService.createCache("frm.TSPolicies",
                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
 
-            clusterContainerService.createCache(WORKSTATUSCACHE,
+            clusterContainerService.createCache(WORK_STATUS_CACHE,
                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL, IClusterServices.cacheMode.ASYNC));
 
-            clusterContainerService.createCache(WORKORDERCACHE,
+            clusterContainerService.createCache(WORK_ORDER_CACHE,
                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL, IClusterServices.cacheMode.ASYNC));
 
         } catch (CacheConfigException cce) {
@@ -1480,18 +1503,18 @@ public class ForwardingRulesManager implements
             log.error("Retrieval of frm.TSPolicies cache failed for Container {}", container.getName());
         }
 
-        map = clusterContainerService.getCache(WORKORDERCACHE);
+        map = clusterContainerService.getCache(WORK_ORDER_CACHE);
         if (map != null) {
             workOrder = (ConcurrentMap<FlowEntryDistributionOrder, FlowEntryInstall>) map;
         } else {
-            log.error("Retrieval of " + WORKORDERCACHE + " cache failed for Container {}", container.getName());
+            log.error("Retrieval of " + WORK_ORDER_CACHE + " cache failed for Container {}", container.getName());
         }
 
-        map = clusterContainerService.getCache(WORKSTATUSCACHE);
+        map = clusterContainerService.getCache(WORK_STATUS_CACHE);
         if (map != null) {
             workStatus = (ConcurrentMap<FlowEntryDistributionOrder, Status>) map;
         } else {
-            log.error("Retrieval of " + WORKSTATUSCACHE + " cache failed for Container {}", container.getName());
+            log.error("Retrieval of " + WORK_STATUS_CACHE + " cache failed for Container {}", container.getName());
         }
     }
 
@@ -1537,7 +1560,7 @@ public class ForwardingRulesManager implements
         boolean multipleFlowPush = false;
         String error;
         Status status;
-        config.setStatus(SUCCESS);
+        config.setStatus(StatusCode.SUCCESS.toString());
 
         // Presence check
         if (flowConfigExists(config)) {
@@ -1615,7 +1638,7 @@ public class ForwardingRulesManager implements
                 continue;
             }
             if (config.getNode().equals(node)) {
-                if (config.installInHw() && !config.getStatus().equals(SUCCESS)) {
+                if (config.installInHw() && !config.getStatus().equals(StatusCode.SUCCESS.toString())) {
                     Status status = this.installFlowEntryAsync(config.getFlowEntry());
                     config.setStatus(status.getDescription());
                 }
@@ -1669,7 +1692,7 @@ public class ForwardingRulesManager implements
                     config.setStatus("Removed from node because in container mode");
                     break;
                 case REMOVED:
-                    config.setStatus(SUCCESS);
+                    config.setStatus(StatusCode.SUCCESS.toString());
                     break;
                 default:
                 }
@@ -1856,7 +1879,7 @@ public class ForwardingRulesManager implements
                                     .installFlowEntry(target.getFlowEntry());
             if (status.isSuccess()) {
                 // Update Configuration database
-                target.setStatus(SUCCESS);
+                target.setStatus(StatusCode.SUCCESS.toString());
                 target.toggleInstallation();
                 staticFlows.put(key, target);
             }
@@ -1921,7 +1944,7 @@ public class ForwardingRulesManager implements
             if (n != null && connectionManager.getLocalityStatus(n) == ConnectionLocality.LOCAL) {
                 Status status = this.removeEntryInternal(flowEntryHw, false);
                 if (!status.isSuccess()) {
-                    log.warn("Failed to remove entry: {}. The failure is: {}", flowEntryHw, status.getDescription());
+                    log.trace("Failed to remove entry: {}. The failure is: {}", flowEntryHw, status.getDescription());
                 }
             } else {
                 log.debug("Not removing entry {} because not connected locally, the remote guy will do it's job",
@@ -2259,12 +2282,12 @@ public class ForwardingRulesManager implements
         List<FlowConfig> flowConfigForNode = getStaticFlows(nodeConnector.getNode());
         for (FlowConfig flowConfig : flowConfigForNode) {
             if (doesFlowContainNodeConnector(flowConfig.getFlow(), nodeConnector)) {
-                if (flowConfig.installInHw() && !flowConfig.getStatus().equals(SUCCESS)) {
+                if (flowConfig.installInHw() && !flowConfig.getStatus().equals(StatusCode.SUCCESS.toString())) {
                     Status status = this.installFlowEntry(flowConfig.getFlowEntry());
                     if (!status.isSuccess()) {
                         flowConfig.setStatus(status.getDescription());
                     } else {
-                        flowConfig.setStatus(SUCCESS);
+                        flowConfig.setStatus(StatusCode.SUCCESS.toString());
                     }
                     updated = true;
                 }
@@ -3127,7 +3150,7 @@ public class ForwardingRulesManager implements
         if (target != null) {
             // Update Configuration database
             target.toggleInstallation();
-            target.setStatus(SUCCESS);
+            target.setStatus(StatusCode.SUCCESS.toString());
             staticFlows.put(key, target);
         }
 
@@ -3245,7 +3268,7 @@ public class ForwardingRulesManager implements
              */
             return;
         }
-        if (cacheName.equals(WORKORDERCACHE)) {
+        if (cacheName.equals(WORK_ORDER_CACHE)) {
             logsync.trace("Got a WorkOrderCacheUpdate for {}", key);
             /*
              * This is the case of one workOrder becoming available, so we need
@@ -3263,7 +3286,7 @@ public class ForwardingRulesManager implements
                 // processing
                 pendingEvents.offer(new WorkOrderEvent(fe, (FlowEntryInstall) new_value));
             }
-        } else if (cacheName.equals(WORKSTATUSCACHE)) {
+        } else if (cacheName.equals(WORK_STATUS_CACHE)) {
             logsync.trace("Got a WorkStatusCacheUpdate for {}", key);
             /*
              * This is the case of one workOrder being completed and a status