On container removal FRM does not uninstall flows 59/1159/1
authorAlessandro Boch <aboch@cisco.com>
Wed, 11 Sep 2013 16:35:36 +0000 (09:35 -0700)
committerAlessandro Boch <aboch@cisco.com>
Wed, 11 Sep 2013 16:52:08 +0000 (09:52 -0700)
ISSUE:
If a container had container flow specified, when it is removed FRM fails to uninstall
the flows that were installed in that container context

ROOT CAUSE:
On FRM stop(), the uninstallAllFlowEntries() function is called.
uninstallAllFlowEntries() does 2 things:
 1) it stores the original FlowEntry elements for later re-install irrespectively
it is called because FRM is being shutdown (container removal) or because controller
is moving to container mode (and this is the default container context) which is a bug.
 2) It uninstall the flows using the removeEntry(FlowEntry fe, ...) function which recomputes
the hw flows to be removed merging fe with the container flows for this container
returned by IContainer service, which is unefficient anyway.

Problem is that when FRM is being stopped because of container removal, IContainer service does no
longer have the container flows for the given container when queried by FRM.

FIX:
- Have uninstallAllFlowEntries() take a parameter to specify if the back up of the original flow entries is needed.
- Have uninstallAllFlowEntries() use the removeEntryInternal() to directly remove the FlowEntryInstall elements, because
  besides of the inefficinecy of recomputing the container flow merged entries there is really no need for it.
- Updated the java docs

Change-Id: If33d80f9593ee81fa58d84dea05514921e143225
Signed-off-by: Alessandro Boch <aboch@cisco.com>
opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java

index 0d0874990e88a5902e510a62ca31aa1294c3d67d..be139317dc9eb3aed2fa1066985cdc4eb152b060 100644 (file)
@@ -1849,27 +1849,38 @@ public class ForwardingRulesManager implements
 
     /**
      * Uninstall all the non-internal Flow Entries present in the software view.
-     * A copy of each entry is stored in the inactive list so that it can be
-     * re-applied when needed. This function is called on the global instance of
-     * FRM only, when the first container is created
+     * If requested, a copy of each original flow entry will be stored in the
+     * inactive list so that it can be re-applied when needed (This is typically
+     * the case when running in the default container and controller moved to
+     * container mode)
+     *
+     * @param preserveFlowEntries
+     *            if true, a copy of each original entry is stored in the
+     *            inactive list
      */
-    private void uninstallAllFlowEntries() {
+    private void uninstallAllFlowEntries(boolean preserveFlowEntries) {
         log.info("Uninstalling all non-internal flows");
 
+        List<FlowEntryInstall> toRemove = new ArrayList<FlowEntryInstall>();
+
         // Store entries / create target list
         for (ConcurrentMap.Entry<FlowEntryInstall, FlowEntryInstall> mapEntry : installedSwView.entrySet()) {
             FlowEntryInstall flowEntries = mapEntry.getValue();
             // Skip internal generated static flows
             if (!flowEntries.isInternal()) {
-                inactiveFlows.put(flowEntries.getOriginal(), flowEntries.getOriginal());
+                toRemove.add(flowEntries);
+                // Store the original entries if requested
+                if (preserveFlowEntries) {
+                    inactiveFlows.put(flowEntries.getOriginal(), flowEntries.getOriginal());
+                }
             }
         }
 
         // Now remove the entries
-        for (FlowEntry flowEntry : inactiveFlows.keySet()) {
-            Status status = this.removeEntry(flowEntry, false);
+        for (FlowEntryInstall flowEntryHw : toRemove) {
+            Status status = this.removeEntryInternal(flowEntryHw, false);
             if (!status.isSuccess()) {
-                log.warn("Failed to remove entry: {}. The failure is: {}", flowEntry, status.getDescription());
+                log.warn("Failed to remove entry: {}. The failure is: {}", flowEntryHw, status.getDescription());
             }
         }
     }
@@ -2472,7 +2483,7 @@ public class ForwardingRulesManager implements
      */
     void stop() {
         stopping = true;
-        uninstallAllFlowEntries();
+        uninstallAllFlowEntries(false);
     }
 
     public void setFlowProgrammerService(IFlowProgrammerService service) {
@@ -2588,8 +2599,15 @@ public class ForwardingRulesManager implements
         }
         switch (update) {
         case ADDED:
+            /*
+             * Controller is moving to container mode. We are in the default
+             * container context, we need to remove all our non-internal flows
+             * to prevent any container isolation breakage. We also need to
+             * preserve our flow so that they can be re-installed if we move
+             * back to non container mode (no containers).
+             */
             this.inContainerMode = true;
-            this.uninstallAllFlowEntries();
+            this.uninstallAllFlowEntries(true);
             break;
         case REMOVED:
             this.inContainerMode = false;