Merge "Controller to listen to expired flow removal message - Added plugin-to-FM...
authorJason Ye <yisye@cisco.com>
Thu, 18 Apr 2013 23:01:30 +0000 (23:01 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 18 Apr 2013 23:01:30 +0000 (23:01 +0000)
22 files changed:
opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/Activator.java
opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManagerImpl.java
opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthbound.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IFlowProgrammerNotifier.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerNotifier.java [new file with mode: 0644]
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6FlowMod.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/authorization/IResourceAuthorization.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerListener.java [new file with mode: 0644]
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginInFlowProgrammerService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginOutFlowProgrammerService.java [new file with mode: 0644]
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchField.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchType.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/topology/IPluginOutTopologyService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/Status.java
opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java
opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/Activator.java
opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/FlowProgrammerService.java

index 9da0970340caa531471e761ebb8e5678330ddfb0..8578e8492e89719ad510931432cec250e589c601 100644 (file)
@@ -21,6 +21,7 @@ import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManage
 import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
 import org.opendaylight.controller.sal.core.IContainer;
 import org.opendaylight.controller.sal.core.IContainerListener;
+import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener;
 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.switchmanager.IInventoryListener;
@@ -98,14 +99,16 @@ public class Activator extends ComponentActivatorAbstractBase {
                         IForwardingRulesManager.class.getName(),
                         IInventoryListener.class.getName(),
                         ICacheUpdateAware.class.getName(),
-                        IConfigurationContainerAware.class.getName() };
+                        IConfigurationContainerAware.class.getName(),
+                        IFlowProgrammerListener.class.getName()};
             } else {
                 interfaces = new String[] {
                         ISwitchManagerAware.class.getName(),
                         IForwardingRulesManager.class.getName(),
                         IInventoryListener.class.getName(),
                         ICacheUpdateAware.class.getName(),
-                        IConfigurationContainerAware.class.getName() };
+                        IConfigurationContainerAware.class.getName(),
+                        IFlowProgrammerListener.class.getName()};
             }
 
             c.setInterface(interfaces, props);
index 6cdc785a196593a20116efdef0976b9d8550355c..58f1e18730c8ee230bc24d3d38786cf2cc7693aa 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -60,6 +59,7 @@ import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.Property;
 import org.opendaylight.controller.sal.core.UpdateType;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener;
 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
 import org.opendaylight.controller.sal.match.Match;
 import org.opendaylight.controller.sal.match.MatchType;
@@ -91,7 +91,8 @@ import org.slf4j.LoggerFactory;
 public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         PortGroupChangeListener, IContainerListener, ISwitchManagerAware,
         IConfigurationContainerAware, IInventoryListener, IObjectReader,
-        ICacheUpdateAware<Long, String>, CommandProvider {
+        ICacheUpdateAware<Long, String>, CommandProvider,
+        IFlowProgrammerListener {
     private static final String SAVE = "Save";
     private static final String NODEDOWN = "Node is Down";
     private static final Logger log = LoggerFactory
@@ -107,18 +108,18 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     private boolean inContainerMode; // being used by default instance only
     /*
      * Flow database. It's the software view of what was installed on the
-     * switch. It is indexed by node. For convenience a version indexed
-     * by group name is also maintained. The core element is a class which
-     * contains the flow entry pushed by the functional modules and the
-     * respective container flow merged version. In absence of container
-     * flows, the two flow entries are the same.
+     * switch. It is indexed by node. For convenience a version indexed by group
+     * name is also maintained. The core element is a class which contains the
+     * flow entry pushed by the functional modules and the respective container
+     * flow merged version. In absence of container flows, the two flow entries
+     * are the same.
      */
     private ConcurrentMap<Node, Set<FlowEntryInstall>> nodeFlows;
     private ConcurrentMap<String, Set<FlowEntryInstall>> groupFlows;
     /*
-     * Inactive flow list. This is for the global instance of FRM
-     * It will contain all the flow entries which were installed on the
-     * global container when the first container is created.
+     * Inactive flow list. This is for the global instance of FRM It will
+     * contain all the flow entries which were installed on the global container
+     * when the first container is created.
      */
     private List<FlowEntry> inactiveFlows;
 
@@ -131,54 +132,56 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     private ISwitchManager switchManager;
 
     /**
-     * Adds a flow entry onto the network node
-     * It runs various validity checks and derive the final container flows
-     * merged entries that will be attempted to be installed
-     *
-     * @param flowEntry the original flow entry application requested to add
+     * Adds a flow entry onto the network node It runs various validity checks
+     * and derive the final container flows merged entries that will be
+     * attempted to be installed
+     * 
+     * @param flowEntry
+     *            the original flow entry application requested to add
      * @return
      */
     private Status addEntry(FlowEntry flowEntry) {
         // Sanity Check
         if (flowEntry == null || flowEntry.getNode() == null) {
-               String msg = "Invalid FlowEntry";
+            String msg = "Invalid FlowEntry";
             log.warn(msg + ": " + flowEntry);
             return new Status(StatusCode.NOTACCEPTABLE, msg);
         }
 
         /*
-         * Derive the container flow merged entries to install
-         * In presence of N container flows, we may end up with
-         * N different entries to install...
+         * Derive the container flow merged entries to install In presence of N
+         * container flows, we may end up with N different entries to install...
          */
-        List<FlowEntryInstall> toInstallList = deriveInstallEntries(flowEntry
-                .clone(), container.getContainerFlows());
+        List<FlowEntryInstall> toInstallList = deriveInstallEntries(
+                flowEntry.clone(), container.getContainerFlows());
 
         // Container Flow conflict Check
         if (toInstallList.isEmpty()) {
-               String msg = "Flow Entry conflicts with all Container Flows";
-               log.warn(msg);
+            String msg = "Flow Entry conflicts with all Container Flows";
+            log.warn(msg);
             return new Status(StatusCode.CONFLICT, msg);
         }
 
         // Derive the list of entries good to be installed
         List<FlowEntryInstall> toInstallSafe = new ArrayList<FlowEntryInstall>();
         for (FlowEntryInstall entry : toInstallList) {
-            // Conflict Check: Verify new entry would not overwrite existing ones
+            // Conflict Check: Verify new entry would not overwrite existing
+            // ones
             if (findMatch(entry.getInstall(), false) != null) {
-                log.warn("Operation Rejected: A flow with same match " + 
-                               "and priority exists on the target node");
+                log.warn("Operation Rejected: A flow with same match "
+                        + "and priority exists on the target node");
                 log.trace("Aborting to install " + entry);
                 continue;
             }
             toInstallSafe.add(entry);
         }
 
-        // Declare failure if all the container flow merged entries clash with existing entries
+        // Declare failure if all the container flow merged entries clash with
+        // existing entries
         if (toInstallSafe.size() == 0) {
-               String msg = "A flow with same match and priority exists " + 
-                               "on the target node";
-               log.warn(msg);
+            String msg = "A flow with same match and priority exists "
+                    + "on the target node";
+            log.warn(msg);
             return new Status(StatusCode.CONFLICT, msg);
         }
 
@@ -188,7 +191,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         for (FlowEntryInstall installEntry : toInstallList) {
 
             // Install and update database
-               Status ret = addEntriesInternal(installEntry);
+            Status ret = addEntriesInternal(installEntry);
 
             if (ret.isSuccess()) {
                 oneSucceded = true;
@@ -206,12 +209,14 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
      * of container flow merged flow entries good to be installed on this
      * container. If the list of container flows is null or empty, the install
      * entry list will contain only one entry, the original flow entry. If the
-     * flow entry is  congruent with all the N container flows, then the output
+     * flow entry is congruent with all the N container flows, then the output
      * install entry list will contain N entries. If the output list is empty,
      * it means the passed flow entry conflicts with all the container flows.
-     *
-     * @param cFlowList The list of container flows
-     * @return the list of container flow merged entries good to be installed on this container
+     * 
+     * @param cFlowList
+     *            The list of container flows
+     * @return the list of container flow merged entries good to be installed on
+     *         this container
      */
     private List<FlowEntryInstall> deriveInstallEntries(FlowEntry request,
             List<ContainerFlow> cFlowList) {
@@ -224,7 +229,8 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             toInstallList.add(new FlowEntryInstall(request.clone(), null));
         } else {
             // Create the list of entries to be installed. If the flow entry is
-            // not congruent with any container flow, no install entries will be created
+            // not congruent with any container flow, no install entries will be
+            // created
             for (ContainerFlow cFlow : container.getContainerFlows()) {
                 if (cFlow.allowsFlow(request.getFlow())) {
                     toInstallList.add(new FlowEntryInstall(request.clone(),
@@ -236,49 +242,50 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     }
 
     /**
-     * Modify a flow entry with a new one
-     * It runs various validity check and derive the final container flows
-     * merged flow entries to work with
-     *
+     * Modify a flow entry with a new one It runs various validity check and
+     * derive the final container flows merged flow entries to work with
+     * 
      * @param currentFlowEntry
      * @param newFlowEntry
      * @return Success or error string
      */
     private Status modifyEntry(FlowEntry currentFlowEntry,
             FlowEntry newFlowEntry) {
-       Status retExt;
+        Status retExt;
 
         // Sanity checks
         if (currentFlowEntry == null || currentFlowEntry.getNode() == null
                 || newFlowEntry == null || newFlowEntry.getNode() == null) {
-               String msg ="Modify: Invalid FlowEntry";
+            String msg = "Modify: Invalid FlowEntry";
             log.warn(msg + ": {} or {} ", currentFlowEntry, newFlowEntry);
             return new Status(StatusCode.NOTACCEPTABLE, msg);
         }
         if (!currentFlowEntry.getNode().equals(newFlowEntry.getNode())
                 || !currentFlowEntry.getFlowName().equals(
                         newFlowEntry.getFlowName())) {
-               String msg = "Modify: Incompatible Flow Entries";
-            log.warn(msg +": {} and {}", currentFlowEntry, newFlowEntry);
+            String msg = "Modify: Incompatible Flow Entries";
+            log.warn(msg + ": {} and {}", currentFlowEntry, newFlowEntry);
             return new Status(StatusCode.NOTACCEPTABLE, msg);
         }
 
         // Equality Check
         if (currentFlowEntry.equals(newFlowEntry)) {
-               String msg = "Modify skipped as flows are the same";
+            String msg = "Modify skipped as flows are the same";
             log.debug(msg + ": " + currentFlowEntry + " and " + newFlowEntry);
             return new Status(StatusCode.SUCCESS, msg);
         }
 
-        // Conflict Check: Verify the new entry would not conflict with another existing one
-        // This is a loose check on the previous original flow entry requests. No check
+        // Conflict Check: Verify the new entry would not conflict with another
+        // existing one
+        // This is a loose check on the previous original flow entry requests.
+        // No check
         // on the container flow merged flow entries (if any) yet
         FlowEntryInstall sameMatchOriginalEntry = findMatch(newFlowEntry, true);
         if (sameMatchOriginalEntry != null
                 && !sameMatchOriginalEntry.getOriginal().equals(
                         currentFlowEntry)) {
-               String msg = "Operation Rejected: Another flow with same match " +
-                               "and priority exists on the target node";
+            String msg = "Operation Rejected: Another flow with same match "
+                    + "and priority exists on the target node";
             log.warn(msg);
             return new Status(StatusCode.CONFLICT, msg);
         }
@@ -290,8 +297,8 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                 newFlowEntry.clone(), container.getContainerFlows());
 
         if (toInstallList.isEmpty()) {
-               String msg = "Modify Operation Rejected: The new entry " + 
-                               "conflicts with all the container flows";
+            String msg = "Modify Operation Rejected: The new entry "
+                    + "conflicts with all the container flows";
             log.warn(msg);
             return new Status(StatusCode.CONFLICT, msg);
         }
@@ -302,32 +309,32 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
          * This is only possible when the new entry and current entry have
          * different match. In this scenario the modification would ultimately
          * be handled as a remove and add operations in the protocol plugin.
-         *
+         * 
          * Also, if any of the new flow entries would clash with an existing
          * one, we cannot proceed with the modify operation, because it would
          * fail for some entries and leave stale entries on the network node.
-         * Modify path can be taken only if it can be performed completely,
-         * for all entries.
-         *
-         * So, for the above two cases, to simplify, let's decouple the modify in:
-         * 1) remove current entries
-         * 2) install new entries
+         * Modify path can be taken only if it can be performed completely, for
+         * all entries.
+         * 
+         * So, for the above two cases, to simplify, let's decouple the modify
+         * in: 1) remove current entries 2) install new entries
          */
         boolean decouple = false;
         if (installedList.size() != toInstallList.size()) {
-            log.info("Modify: New flow entry does not satisfy the same " +
-                    "number of container flows as the original entry does");
+            log.info("Modify: New flow entry does not satisfy the same "
+                    "number of container flows as the original entry does");
             decouple = true;
         }
         List<FlowEntryInstall> toInstallSafe = new ArrayList<FlowEntryInstall>();
         for (FlowEntryInstall installEntry : toInstallList) {
-            // Conflict Check: Verify the new entry would not overwrite another existing one
-            FlowEntryInstall sameMatchEntry = findMatch(installEntry
-                    .getInstall(), false);
+            // Conflict Check: Verify the new entry would not overwrite another
+            // existing one
+            FlowEntryInstall sameMatchEntry = findMatch(
+                    installEntry.getInstall(), false);
             if (sameMatchEntry != null
                     && !sameMatchEntry.getOriginal().equals(currentFlowEntry)) {
-                log.info("Modify: new container flow merged flow entry " + 
-                    "clashes with existing flow");
+                log.info("Modify: new container flow merged flow entry "
+                        + "clashes with existing flow");
                 decouple = true;
             } else {
                 toInstallSafe.add(installEntry);
@@ -347,13 +354,13 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             /*
              * The two list have the same size and the entries to install do not
              * clash with any existing flow on the network node. We assume here
-             * (and might be wrong) that the same container flows that were satisfied
-             * by the current entries are the same that are satisfied by the new
-             * entries. Let's take the risk for now.
-             *
+             * (and might be wrong) that the same container flows that were
+             * satisfied by the current entries are the same that are satisfied
+             * by the new entries. Let's take the risk for now.
+             * 
              * Note: modification has to be complete. If any entry modification
-             * fails, we need to stop, restore the already modified entries,
-             * and declare failure.
+             * fails, we need to stop, restore the already modified entries, and
+             * declare failure.
              */
             Status retModify;
             int i = 0;
@@ -370,8 +377,8 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             }
             // Check if uncompleted modify
             if (i < size) {
-                log.warn("Unable to perform a complete modify for all " + 
-                               "the container flows merged entries");
+                log.warn("Unable to perform a complete modify for all "
+                        + "the container flows merged entries");
                 // Restore original entries
                 int j = 0;
                 while (j < i) {
@@ -386,7 +393,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                 }
                 // Fatal error, recovery failed
                 if (j < i) {
-                       String msg = "Flow recovery failed ! Unrecoverable Error";
+                    String msg = "Flow recovery failed ! Unrecoverable Error";
                     log.error(msg);
                     return new Status(StatusCode.INTERNALERROR, msg);
                 }
@@ -397,9 +404,9 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
 
     /**
      * This is the function that modifies the final container flows merged
-     * entries on the network node and update the database. It expects that
-     * all the  validity checks are passed
-     *
+     * entries on the network node and update the database. It expects that all
+     * the validity checks are passed
+     * 
      * @param currentEntries
      * @param newEntries
      * @return
@@ -412,12 +419,13 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                         .getFlow());
 
         if (!status.isSuccess()) {
-            log.warn("SDN Plugin failed to program the flow: " + status.getDescription());
+            log.warn("SDN Plugin failed to program the flow: "
+                    + status.getDescription());
             return status;
         }
 
-        log.trace("Modified {} => {}", currentEntries.getInstall(), newEntries
-                .getInstall());
+        log.trace("Modified {} => {}", currentEntries.getInstall(),
+                newEntries.getInstall());
 
         // Update DB
         updateLocalDatabase(currentEntries, false);
@@ -429,29 +437,29 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     /**
      * Remove a flow entry. If the entry is not present in the software view
      * (entry or node not present), it return successfully
-     *
+     * 
      * @param flowEntry
      * @return
      */
     private Status removeEntry(FlowEntry flowEntry) {
         Status error = new Status(null, null);
-        
+
         // Sanity Check
         if (flowEntry == null || flowEntry.getNode() == null) {
-               String msg = "Invalid FlowEntry";
+            String msg = "Invalid FlowEntry";
             log.warn(msg + ": " + flowEntry);
             return new Status(StatusCode.NOTACCEPTABLE, msg);
         }
 
         // Derive the container flows merged installed entries
-        List<FlowEntryInstall> installedList = deriveInstallEntries(flowEntry
-                .clone(), container.getContainerFlows());
+        List<FlowEntryInstall> installedList = deriveInstallEntries(
+                flowEntry.clone(), container.getContainerFlows());
 
         Set<FlowEntryInstall> flowsOnNode = nodeFlows.get(flowEntry.getNode());
         boolean atLeastOneRemoved = false;
         for (FlowEntryInstall entry : installedList) {
             if (flowsOnNode == null) {
-               String msg = "Removal skipped (Node down)";
+                String msg = "Removal skipped (Node down or Flow not on Node)";
                 log.debug(msg + " for flow entry " + flowEntry);
                 return new Status(StatusCode.SUCCESS, msg);
             }
@@ -483,20 +491,21 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         }
 
         /*
-         * No worries if full removal failed. Consistency checker will
-         * take care of removing the stale entries later, or adjusting
-         * the software database if not in sync with hardware
+         * No worries if full removal failed. Consistency checker will take care
+         * of removing the stale entries later, or adjusting the software
+         * database if not in sync with hardware
          */
-        return (atLeastOneRemoved) ? 
-                       new Status(StatusCode.SUCCESS, null) : error;
+        return (atLeastOneRemoved) ? new Status(StatusCode.SUCCESS, null)
+                : error;
     }
 
     /**
      * This is the function that removes the final container flows merged entry
      * from the network node and update the database. It expects that all the
      * validity checks are passed
-     *
-     * @param entry the FlowEntryInstall
+     * 
+     * @param entry
+     *            the FlowEntryInstall
      * @return "Success" or error string
      */
     private Status removeEntryInternal(FlowEntryInstall entry) {
@@ -504,13 +513,12 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         entry.toBeDeleted();
 
         // Remove from node
-        Status status = 
-                       programmer.removeFlow(entry.getNode(), 
-                                       entry.getInstall().getFlow());
+        Status status = programmer.removeFlow(entry.getNode(), entry
+                .getInstall().getFlow());
 
         if (!status.isSuccess()) {
-            log.warn("SDN Plugin failed to remove the flow: " + 
-                       status.getDescription());
+            log.warn("SDN Plugin failed to remove the flow: "
+                    + status.getDescription());
             return status;
         }
         log.trace("Removed  {}", entry.getInstall());
@@ -526,18 +534,19 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
      * on the network node and updates the database. It expects that all the
      * validity and conflict checks are passed. That means it does not check
      * whether this flow would conflict or overwrite an existing one.
-     *
-     * @param entry the FlowEntryInstall
+     * 
+     * @param entry
+     *            the FlowEntryInstall
      * @return "Success" or error string
      */
     private Status addEntriesInternal(FlowEntryInstall entry) {
         // Install the flow on the network node
-       Status status = programmer.addFlow(entry.getNode(), 
-                       entry.getInstall().getFlow());
+        Status status = programmer.addFlow(entry.getNode(), entry.getInstall()
+                .getFlow());
 
         if (!status.isSuccess()) {
-            log.warn("SDN Plugin failed to program the flow: " + 
-                       status.getDescription());
+            log.warn("SDN Plugin failed to program the flow: "
+                    + status.getDescription());
             return status;
         }
 
@@ -550,19 +559,21 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     }
 
     /**
-     * Returns true if the flow conflicts with all the container's flows.
-     * This means that if the function returns true, the passed flow entry
-     * is congruent with at least one container flow, hence it is good to
-     * be installed on this container.
-     *
+     * Returns true if the flow conflicts with all the container's flows. This
+     * means that if the function returns true, the passed flow entry is
+     * congruent with at least one container flow, hence it is good to be
+     * installed on this container.
+     * 
      * @param flowEntry
-     * @return true if flow conflicts with all the container flows, false otherwise
+     * @return true if flow conflicts with all the container flows, false
+     *         otherwise
      */
     private boolean entryConflictsWithContainerFlows(FlowEntry flowEntry) {
         List<ContainerFlow> cFlowList = container.getContainerFlows();
 
         // Validity check and avoid unnecessary computation
-        // Also takes care of default container where no container flows are present
+        // Also takes care of default container where no container flows are
+        // present
         if (cFlowList == null || cFlowList.isEmpty()) {
             return false;
         }
@@ -702,9 +713,9 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
 
     @Override
     public Status installFlowEntry(FlowEntry flowEntry) {
-       Status status;
+        Status status;
         if (inContainerMode) {
-               String msg = "Controller in container mode: Install Refused";
+            String msg = "Controller in container mode: Install Refused";
             status = new Status(StatusCode.NOTACCEPTABLE, msg);
             log.warn(msg);
         } else {
@@ -715,13 +726,13 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
 
     @Override
     public Status uninstallFlowEntry(FlowEntry entry) {
-       Status status;
+        Status status;
         if (inContainerMode) {
-               String msg = "Controller in container mode: Uninstall Refused";
+            String msg = "Controller in container mode: Uninstall Refused";
             status = new Status(StatusCode.NOTACCEPTABLE, msg);
             log.warn(msg);
         } else {
-               status = removeEntry(entry);
+            status = removeEntry(entry);
         }
         return status;
     }
@@ -729,7 +740,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     @Override
     public Status modifyFlowEntry(FlowEntry currentFlowEntry,
             FlowEntry newFlowEntry) {
-       Status status = null;
+        Status status = null;
         if (inContainerMode) {
             String msg = "Controller in container mode: Modify Refused";
             status = new Status(StatusCode.NOTACCEPTABLE, msg);
@@ -745,11 +756,11 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         /*
          * Run a loose check on the installed entries to decide whether to go
          * with a add or modify method. A loose check means only check against
-         * the original flow entry requests and not against the installed
-         * flow entries which are the result of the original entry merged with
-         * the container flow(s) (if any). The modifyFlowEntry method in
-         * presence of conflicts with the Container flows (if any) would revert
-         * back to a delete + add pattern
+         * the original flow entry requests and not against the installed flow
+         * entries which are the result of the original entry merged with the
+         * container flow(s) (if any). The modifyFlowEntry method in presence of
+         * conflicts with the Container flows (if any) would revert back to a
+         * delete + add pattern
          */
         FlowEntryInstall currentFlowEntries = findMatch(newFlowEntry, true);
 
@@ -762,16 +773,18 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     }
 
     /**
-     * Try to find in the database if a Flow with the same Match and priority
-     * of the passed one already exists for the specified network node.
-     * Flow, priority and network node are all specified in the FlowEntry
-     * If found, the respective FlowEntryInstall Object is returned
-     *
-     * @param flowEntry the FlowEntry to be tested against the ones installed
-     * @param looseCheck if true, the function will run the check against the
-     *          original flow entry portion of the installed entries
+     * Try to find in the database if a Flow with the same Match and priority of
+     * the passed one already exists for the specified network node. Flow,
+     * priority and network node are all specified in the FlowEntry If found,
+     * the respective FlowEntryInstall Object is returned
+     * 
+     * @param flowEntry
+     *            the FlowEntry to be tested against the ones installed
+     * @param looseCheck
+     *            if true, the function will run the check against the original
+     *            flow entry portion of the installed entries
      * @return null if not found, otherwise the FlowEntryInstall which contains
-     *          the existing flow entry
+     *         the existing flow entry
      */
     private FlowEntryInstall findMatch(FlowEntry flowEntry, boolean looseCheck) {
         Flow flow = flowEntry.getFlow();
@@ -797,12 +810,11 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     }
 
     /**
-     * Updates all installed flows because the container flow got updated
-     * This is obtained in two phases on per node basis:
-     * 1) Uninstall of all flows
-     * 2) Reinstall of all flows
-     * This is needed because a new container flows merged flow may conflict with an existing
-     * old container flows merged flow on the network node
+     * Updates all installed flows because the container flow got updated This
+     * is obtained in two phases on per node basis: 1) Uninstall of all flows 2)
+     * Reinstall of all flows This is needed because a new container flows
+     * merged flow may conflict with an existing old container flows merged flow
+     * on the network node
      */
     private void updateFlowsContainerFlow() {
         List<FlowEntryInstall> oldCouples = new ArrayList<FlowEntryInstall>();
@@ -814,16 +826,19 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             if (entry.getValue() == null) {
                 continue;
             }
-            // Create a set of old entries and one of original entries to be reinstalled
+            // Create a set of old entries and one of original entries to be
+            // reinstalled
             for (FlowEntryInstall oldCouple : entry.getValue()) {
                 oldCouples.add(oldCouple);
                 toReinstall.add(oldCouple.getOriginal());
             }
-            // Remove the old couples. No validity checks to be run, use the internal remove
+            // Remove the old couples. No validity checks to be run, use the
+            // internal remove
             for (FlowEntryInstall oldCouple : oldCouples) {
                 this.removeEntryInternal(oldCouple);
             }
-            // Reinstall the original flow entries, via the regular path: new cFlow merge + validations
+            // Reinstall the original flow entries, via the regular path: new
+            // cFlow merge + validations
             for (FlowEntry flowEntry : toReinstall) {
                 this.installFlowEntry(flowEntry);
             }
@@ -919,7 +934,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                             flowName);
                 } else {
                     log.warn("Failed to add ports {} to Flow entry {}: "
-                            + error.getDescription(), portList, 
+                            + error.getDescription(), portList,
                             currentFlowEntry.toString());
                 }
                 return;
@@ -949,16 +964,15 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                             flowName);
                 } else {
                     log.warn("Failed to remove ports {} from Flow entry {}: "
-                            + status.getDescription(), portList, 
+                            + status.getDescription(), portList,
                             currentFlowEntry.toString());
                 }
                 return;
             }
         }
-        log
-                .warn(
-                        "Failed to remove ports from Flow {} on Node {}: Entry Not Found",
-                        flowName, node);
+        log.warn(
+                "Failed to remove ports from Flow {} on Node {}: Entry Not Found",
+                flowName, node);
     }
 
     /*
@@ -979,10 +993,9 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             }
         }
         if (currentFlowEntry == null) {
-            log
-                    .warn(
-                            "Failed to replace output port for flow {} on node {}: Entry Not Found",
-                            flowName, node);
+            log.warn(
+                    "Failed to replace output port for flow {} on node {}: Entry Not Found",
+                    flowName, node);
             return;
         }
 
@@ -1036,37 +1049,36 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     @SuppressWarnings("deprecation")
     private void allocateCaches() {
         if (this.clusterContainerService == null) {
-            log
-                    .warn("Un-initialized clusterContainerService, can't create cache");
+            log.warn("Un-initialized clusterContainerService, can't create cache");
             return;
         }
 
         log.debug("FRM allocateCaches for Container {}", container);
 
         try {
-            clusterContainerService.createCache("frm.nodeFlows", EnumSet
-                    .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+            clusterContainerService.createCache("frm.nodeFlows",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
 
-            clusterContainerService.createCache("frm.groupFlows", EnumSet
-                    .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+            clusterContainerService.createCache("frm.groupFlows",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
 
-            clusterContainerService.createCache("frm.staticFlows", EnumSet
-                    .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+            clusterContainerService.createCache("frm.staticFlows",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
 
-            clusterContainerService.createCache("frm.flowsSaveEvent", EnumSet
-                    .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+            clusterContainerService.createCache("frm.flowsSaveEvent",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
 
             clusterContainerService.createCache("frm.staticFlowsOrdinal",
                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
 
-            clusterContainerService.createCache("frm.portGroupConfigs", EnumSet
-                    .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+            clusterContainerService.createCache("frm.portGroupConfigs",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
 
-            clusterContainerService.createCache("frm.portGroupData", EnumSet
-                    .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+            clusterContainerService.createCache("frm.portGroupData",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
 
-            clusterContainerService.createCache("frm.TSPolicies", EnumSet
-                    .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+            clusterContainerService.createCache("frm.TSPolicies",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
 
         } catch (CacheConfigException cce) {
             log.error("FRM CacheConfigException");
@@ -1075,13 +1087,12 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         }
     }
 
-    @SuppressWarnings( { "unchecked", "deprecation" })
+    @SuppressWarnings({ "unchecked", "deprecation" })
     private void retrieveCaches() {
         ConcurrentMap<?, ?> map;
 
         if (this.clusterContainerService == null) {
-            log
-                    .warn("un-initialized clusterContainerService, can't retrieve cache");
+            log.warn("un-initialized clusterContainerService, can't retrieve cache");
             return;
         }
 
@@ -1091,89 +1102,80 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         if (map != null) {
             nodeFlows = (ConcurrentMap<Node, Set<FlowEntryInstall>>) map;
         } else {
-            log
-                    .error(
-                            "FRM Cache frm.nodeFlows allocation failed for Container {}",
-                            container);
+            log.error(
+                    "FRM Cache frm.nodeFlows allocation failed for Container {}",
+                    container);
         }
 
         map = clusterContainerService.getCache("frm.groupFlows");
         if (map != null) {
             groupFlows = (ConcurrentMap<String, Set<FlowEntryInstall>>) map;
         } else {
-            log
-                    .error(
-                            "FRM Cache frm.groupFlows allocation failed for Container {}",
-                            container);
+            log.error(
+                    "FRM Cache frm.groupFlows allocation failed for Container {}",
+                    container);
         }
 
         map = clusterContainerService.getCache("frm.staticFlows");
         if (map != null) {
             staticFlows = (ConcurrentMap<Integer, FlowConfig>) map;
         } else {
-            log
-                    .error(
-                            "FRM Cache frm.staticFlows allocation failed for Container {}",
-                            container);
+            log.error(
+                    "FRM Cache frm.staticFlows allocation failed for Container {}",
+                    container);
         }
 
         map = clusterContainerService.getCache("frm.flowsSaveEvent");
         if (map != null) {
             flowsSaveEvent = (ConcurrentMap<Long, String>) map;
         } else {
-            log
-                    .error(
-                            "FRM Cache frm.flowsSaveEvent allocation failed for Container {}",
-                            container);
+            log.error(
+                    "FRM Cache frm.flowsSaveEvent allocation failed for Container {}",
+                    container);
         }
 
         map = clusterContainerService.getCache("frm.staticFlowsOrdinal");
         if (map != null) {
             staticFlowsOrdinal = (ConcurrentMap<Integer, Integer>) map;
         } else {
-            log
-                    .error(
-                            "FRM Cache frm.staticFlowsOrdinal allocation failed for Container {}",
-                            container);
+            log.error(
+                    "FRM Cache frm.staticFlowsOrdinal allocation failed for Container {}",
+                    container);
         }
 
         map = clusterContainerService.getCache("frm.portGroupConfigs");
         if (map != null) {
             portGroupConfigs = (ConcurrentMap<String, PortGroupConfig>) map;
         } else {
-            log
-                    .error(
-                            "FRM Cache frm.portGroupConfigs allocation failed for Container {}",
-                            container);
+            log.error(
+                    "FRM Cache frm.portGroupConfigs allocation failed for Container {}",
+                    container);
         }
 
         map = clusterContainerService.getCache("frm.portGroupData");
         if (map != null) {
             portGroupData = (ConcurrentMap<PortGroupConfig, Map<Node, PortGroup>>) map;
         } else {
-            log
-                    .error(
-                            "FRM Cache frm.portGroupData allocation failed for Container {}",
-                            container);
+            log.error(
+                    "FRM Cache frm.portGroupData allocation failed for Container {}",
+                    container);
         }
 
         map = clusterContainerService.getCache("frm.TSPolicies");
         if (map != null) {
             TSPolicies = (ConcurrentMap<String, Object>) map;
         } else {
-            log
-                    .error(
-                            "FRM Cache frm.TSPolicies allocation failed for Container {}",
-                            container);
+            log.error(
+                    "FRM Cache frm.TSPolicies allocation failed for Container {}",
+                    container);
         }
 
     }
 
     @SuppressWarnings("deprecation")
-       private void destroyCaches() {
+    private void destroyCaches() {
         if (this.clusterContainerService == null) {
-            log
-                    .warn("Un-initialized clusterContainerService, can't destroy cache");
+            log.warn("Un-initialized clusterContainerService, can't destroy cache");
             return;
         }
 
@@ -1263,9 +1265,9 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
          * multiple entry configuration (PortGroup) and hardware installation is
          * NOT done directly on this event. 3. The User prefers to retain the
          * configuration in Controller and skip hardware installation.
-         *
+         * 
          * Hence it is safe to update the StaticFlow DB at this point.
-         *
+         * 
          * Note : For the case of PortGrouping, it is essential to have this DB
          * populated before the PortGroupListeners can query for the DB
          * triggered using portGroupChanged event...
@@ -1293,7 +1295,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             if (config.getNode().equals(node)) {
                 if (config.installInHw()
                         && !config.getStatus().equals(
-                                       StatusCode.SUCCESS.toString())) {
+                                StatusCode.SUCCESS.toString())) {
                     Status status = this.addEntry(config.getFlowEntry());
                     config.setStatus(status.getDescription());
                 }
@@ -1305,27 +1307,27 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         log.trace("Updating Static Flow configs on node down: " + node);
 
         List<Integer> toRemove = new ArrayList<Integer>();
-        for (Entry<Integer,FlowConfig> entry : staticFlows.entrySet()) {
+        for (Entry<Integer, FlowConfig> entry : staticFlows.entrySet()) {
 
-               FlowConfig config = entry.getValue();
+            FlowConfig config = entry.getValue();
 
             if (config.isPortGroupEnabled()) {
                 continue;
             }
-            
+
             if (config.installInHw() && config.getNode().equals(node)) {
-               if (config.isInternalFlow()) {
-                       // Take note of this controller generated static flow
-                       toRemove.add(entry.getKey());
-               } else {
-                       config.setStatus(NODEDOWN);
-               }
+                if (config.isInternalFlow()) {
+                    // Take note of this controller generated static flow
+                    toRemove.add(entry.getKey());
+                } else {
+                    config.setStatus(NODEDOWN);
+                }
             }
         }
-        // Remove controller generated static flows for this node 
+        // Remove controller generated static flows for this node
         for (Integer index : toRemove) {
-               staticFlows.remove(index);
-        }        
+            staticFlows.remove(index);
+        }
     }
 
     private void updateStaticFlowConfigsOnContainerModeChange(UpdateType update) {
@@ -1339,8 +1341,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             if (config.installInHw()) {
                 switch (update) {
                 case ADDED:
-                    config
-                            .setStatus("Removed from node because in container mode");
+                    config.setStatus("Removed from node because in container mode");
                     break;
                 case REMOVED:
                     config.setStatus(StatusCode.SUCCESS.toString());
@@ -1354,15 +1355,15 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     public Status removeStaticFlow(FlowConfig config) {
         /*
          * No config.isInternal() check as NB does not take this path and GUI
-         * cannot issue a delete on an internal generated flow. We need this path
-         * to be accessible when switch mode is changed from proactive to
+         * cannot issue a delete on an internal generated flow. We need this
+         * path to be accessible when switch mode is changed from proactive to
          * reactive, so that we can remove the internal generated LLDP and ARP
          * punt flows
          */
         for (Map.Entry<Integer, FlowConfig> entry : staticFlows.entrySet()) {
             if (entry.getValue().isByNameAndNodeIdEqual(config)) {
                 // Program the network node
-               Status status = this.removeEntry(config.getFlowEntry());
+                Status status = this.removeEntry(config.getFlowEntry());
                 // Update configuration database if programming was successful
                 if (status.isSuccess()) {
                     staticFlows.remove(entry.getKey());
@@ -1380,14 +1381,14 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     public Status removeStaticFlow(String name, Node node) {
         for (Map.Entry<Integer, FlowConfig> mapEntry : staticFlows.entrySet()) {
             FlowConfig entry = mapEntry.getValue();
-            Status status = new Status(null,null);
+            Status status = new Status(null, null);
             if (entry.isByNameAndNodeIdEqual(name, node)) {
                 // Validity check for api3 entry point
                 if (entry.isInternalFlow()) {
-                       String msg = "Invalid operation: Controller generated " +
-                                       "flow cannot be deleted";
-                       log.warn(msg);
-                       return new Status(StatusCode.NOTACCEPTABLE, msg);
+                    String msg = "Invalid operation: Controller generated "
+                            + "flow cannot be deleted";
+                    log.warn(msg);
+                    return new Status(StatusCode.NOTACCEPTABLE, msg);
                 }
                 if (!entry.isPortGroupEnabled()) {
                     // Program the network node
@@ -1409,17 +1410,16 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     public Status modifyStaticFlow(FlowConfig newFlowConfig) {
         // Validity check for api3 entry point
         if (newFlowConfig.isInternalFlow()) {
-               String msg = "Invalid operation: Controller generated flow " + 
-                                       "cannot be modified";
-               log.warn(msg);
+            String msg = "Invalid operation: Controller generated flow "
+                    + "cannot be modified";
+            log.warn(msg);
             return new Status(StatusCode.NOTACCEPTABLE, msg);
         }
 
         // Validity Check
         StringBuffer resultStr = new StringBuffer();
         if (!newFlowConfig.isValid(container, resultStr)) {
-            String msg = "Invalid Configuration (" + resultStr.toString()
-                    + ")";
+            String msg = "Invalid Configuration (" + resultStr.toString() + ")";
             newFlowConfig.setStatus(msg);
             log.warn(msg);
             return new Status(StatusCode.BADREQUEST, msg);
@@ -1438,22 +1438,22 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         }
 
         if (oldFlowConfig == null) {
-               String msg = "Attempt to modify a non existing static flow";
-               log.warn(msg);
-               return new Status(StatusCode.NOTFOUND, msg);
+            String msg = "Attempt to modify a non existing static flow";
+            log.warn(msg);
+            return new Status(StatusCode.NOTFOUND, msg);
         }
 
         // Do not attempt to reinstall the flow, warn user
         if (newFlowConfig.equals(oldFlowConfig)) {
-               String msg = "No modification detected";
-               log.info("Static flow modification skipped: " + msg);
+            String msg = "No modification detected";
+            log.info("Static flow modification skipped: " + msg);
             return new Status(StatusCode.SUCCESS, msg);
         }
 
         // If flow is installed, program the network node
         Status status = new Status(StatusCode.SUCCESS, "Saved in config");
         if (oldFlowConfig.installInHw()) {
-               status = this.modifyEntry(oldFlowConfig.getFlowEntry(),
+            status = this.modifyEntry(oldFlowConfig.getFlowEntry(),
                     newFlowConfig.getFlowEntry());
         }
 
@@ -1466,26 +1466,24 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         return status;
     }
 
+    @Override
+    public Status toggleStaticFlowStatus(String name, Node node) {
+        return toggleStaticFlowStatus(getStaticFlow(name, node));
+    }
 
-
-       @Override
-       public Status toggleStaticFlowStatus(String name, Node node) {
-               return toggleStaticFlowStatus(getStaticFlow(name, node));
-       }
-       
     @Override
     public Status toggleStaticFlowStatus(FlowConfig config) {
-       if (config == null) {
-               String msg = "Invalid request: null flow config";
-               log.warn(msg);
-               return new Status(StatusCode.BADREQUEST, msg);
-       }
+        if (config == null) {
+            String msg = "Invalid request: null flow config";
+            log.warn(msg);
+            return new Status(StatusCode.BADREQUEST, msg);
+        }
         // Validity check for api3 entry point
         if (config.isInternalFlow()) {
-               String msg = "Invalid operation: Controller generated flow " +
-                               "cannot be modified";
-               log.warn(msg);
-               return new Status(StatusCode.NOTACCEPTABLE, msg);
+            String msg = "Invalid operation: Controller generated flow "
+                    + "cannot be modified";
+            log.warn(msg);
+            return new Status(StatusCode.NOTACCEPTABLE, msg);
         }
 
         for (Map.Entry<Integer, FlowConfig> entry : staticFlows.entrySet()) {
@@ -1510,15 +1508,14 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
             }
         }
         return new Status(StatusCode.NOTFOUND,
-                       "Unable to locate the entry. Failed to toggle status");
+                "Unable to locate the entry. Failed to toggle status");
     }
 
     /**
-     * Uninstall all the 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 default container instance of FRM only
-     * when the first container is created
+     * Uninstall all the 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 default container instance of
+     * FRM only when the first container is created
      */
     private void uninstallAllFlowEntries() {
         log.info("Uninstalling all flows");
@@ -1535,26 +1532,27 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         for (FlowEntry flowEntry : inactiveFlows) {
             Status status = this.removeEntry(flowEntry);
             if (!status.isSuccess()) {
-                log.warn("Failed to remove entry: {}: " + 
-                               status.getDescription(), flowEntry);
+                log.warn(
+                        "Failed to remove entry: {}: "
+                                + status.getDescription(), flowEntry);
             }
         }
     }
 
     /**
-     * Re-install all the Flow Entries present in the inactive list
-     * The inactive list will be empty at the end of this call
-     * This function is called on the default container instance of FRM only
-     * when the last container is deleted
+     * Re-install all the Flow Entries present in the inactive list The inactive
+     * list will be empty at the end of this call This function is called on the
+     * default container instance of FRM only when the last container is deleted
      */
     private void reinstallAllFlowEntries() {
         log.info("Reinstalling all inactive flows");
 
         for (FlowEntry flowEntry : this.inactiveFlows) {
-               Status status = this.addEntry(flowEntry);
+            Status status = this.addEntry(flowEntry);
             if (!status.isSuccess()) {
-                log.warn("Failed to install entry: {}: " + 
-                               status.getDescription(), flowEntry);
+                log.warn(
+                        "Failed to install entry: {}: "
+                                + status.getDescription(), flowEntry);
             }
         }
 
@@ -1746,8 +1744,9 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         allowLLDP.setName("**Punt LLDP");
         allowLLDP.setPriority("1");
         allowLLDP.setNode(node);
-        allowLLDP.setEtherType("0x"
-                               + Integer.toHexString(EtherTypes.LLDP.intValue())
+        allowLLDP
+                .setEtherType("0x"
+                        + Integer.toHexString(EtherTypes.LLDP.intValue())
                                 .toUpperCase());
         allowLLDP.setActions(puntAction);
         defaultConfigs.add(allowLLDP);
@@ -1776,7 +1775,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
 
     /**
      * Remove from the databases all the flows installed on the node
-     *
+     * 
      * @param node
      */
     private synchronized void cleanDatabaseForNode(Node node) {
@@ -1819,10 +1818,10 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     public void notifyNode(Node node, UpdateType type,
             Map<String, Property> propMap) {
         switch (type) {
-        case ADDED: 
+        case ADDED:
             addStaticFlowsToSwitch(node);
             break;
-        case REMOVED:          
+        case REMOVED:
             cleanDatabaseForNode(node);
             updateStaticFlowConfigsOnNodeDown(node);
             break;
@@ -1833,7 +1832,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
 
     @Override
     public void notifyNodeConnector(NodeConnector nodeConnector,
-               UpdateType type, Map<String, Property> propMap) {
+            UpdateType type, Map<String, Property> propMap) {
     }
 
     private FlowConfig getDerivedFlowConfig(FlowConfig original,
@@ -1887,8 +1886,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     @Override
     public void portGroupChanged(PortGroupConfig config,
             Map<Node, PortGroup> data, boolean add) {
-        log.info("PortGroup Changed for :" + config + " Data: "
-                 + portGroupData);
+        log.info("PortGroup Changed for :" + config + " Data: " + portGroupData);
         Map<Node, PortGroup> existingData = portGroupData.get(config);
         if (existingData != null) {
             for (Map.Entry<Node, PortGroup> entry : data.entrySet()) {
@@ -1896,20 +1894,20 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
                 if (existingPortGroup == null) {
                     if (add) {
                         existingData.put(entry.getKey(), entry.getValue());
-                        addPortGroupFlows(config, entry.getKey(), entry
-                                .getValue());
+                        addPortGroupFlows(config, entry.getKey(),
+                                entry.getValue());
                     }
                 } else {
                     if (add) {
                         existingPortGroup.getPorts().addAll(
                                 entry.getValue().getPorts());
-                        addPortGroupFlows(config, entry.getKey(), entry
-                                .getValue());
+                        addPortGroupFlows(config, entry.getKey(),
+                                entry.getValue());
                     } else {
                         existingPortGroup.getPorts().removeAll(
                                 entry.getValue().getPorts());
-                        removePortGroupFlows(config, entry.getKey(), entry
-                                .getValue());
+                        removePortGroupFlows(config, entry.getKey(),
+                                entry.getValue());
                     }
                 }
             }
@@ -2063,15 +2061,15 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     /**
      * Function called by the dependency manager when all the required
      * dependencies are satisfied
-     *
+     * 
      */
     void init() {
         frmAware = Collections
                 .synchronizedSet(new HashSet<IForwardingRulesManagerAware>());
-        frmFileName = GlobalConstants.STARTUPHOME.toString() + "frm_staticflows_"
-                + this.getContainerName() + ".conf";
-        portGroupFileName = GlobalConstants.STARTUPHOME.toString() + "portgroup_"
-                + this.getContainerName() + ".conf";
+        frmFileName = GlobalConstants.STARTUPHOME.toString()
+                + "frm_staticflows_" + this.getContainerName() + ".conf";
+        portGroupFileName = GlobalConstants.STARTUPHOME.toString()
+                + "portgroup_" + this.getContainerName() + ".conf";
 
         inContainerMode = false;
 
@@ -2098,7 +2096,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
      * Function called by the dependency manager when at least one dependency
      * become unsatisfied or when the component is shutting down because for
      * example bundle is being stopped.
-     *
+     * 
      */
     void destroy() {
         destroyCaches();
@@ -2107,7 +2105,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     /**
      * Function called by dependency manager after "init ()" is called and after
      * the services provided by the class are registered in the service registry
-     *
+     * 
      */
     void start() {
         /*
@@ -2123,7 +2121,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
      * Function called by the dependency manager before the services exported by
      * the component are unregistered, this will be followed by a "destroy ()"
      * calls
-     *
+     * 
      */
     void stop() {
     }
@@ -2158,8 +2156,8 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
     public void containerFlowUpdated(String containerName,
             ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) {
         /*
-         * Whether it is an addition or removal, we have to recompute the
-         * merged flows entries taking into account all the current container flows
+         * Whether it is an addition or removal, we have to recompute the merged
+         * flows entries taking into account all the current container flows
          * because flow merging is not an injective function
          */
         updateFlowsContainerFlow();
@@ -2315,7 +2313,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
 
     @Override
     public Status saveConfiguration() {
-        return  saveConfig();
+        return saveConfig();
     }
 
     public void _frmNodeFlows(CommandInterpreter ci) {
@@ -2361,4 +2359,28 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager,
         }
     }
 
+    @Override
+    public void flowRemoved(Node node, Flow flow) {
+        log.trace("Received flow removed notification on {} for {}", node, flow);
+        // For flow entry identification, only match and priority matter
+        FlowEntry toFind = new FlowEntry("any", "any", flow, node);
+        FlowEntryInstall installedEntry = this.findMatch(toFind, false);
+        if (installedEntry == null) {
+            log.trace("Entry is not know to us");
+            return;
+        }
+
+        // Update Static flow status
+        for (Map.Entry<Integer, FlowConfig> entry : staticFlows.entrySet()) {
+            FlowConfig conf = entry.getValue();
+            if (conf.isByNameAndNodeIdEqual(installedEntry.getFlowName(), node)) {
+                // Update Configuration database
+                conf.toggleStatus();
+                break;
+            }
+        }
+        // Update software views
+        this.updateLocalDatabase(installedEntry, false);
+    }
+
 }
index d79c4dab898d4dbe7de2685514cd605e3cbf4113..2275ee98da23f3ae7331f6783ec340187634eb50 100644 (file)
@@ -14,6 +14,7 @@ import java.net.UnknownHostException;
 import java.util.List;
 import java.util.Set;
 
+import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.DefaultValue;
diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IFlowProgrammerNotifier.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IFlowProgrammerNotifier.java
new file mode 100644 (file)
index 0000000..3071765
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow;
+
+import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService;
+
+/**
+ * Interface which defines the methods exposed by the Flow Programmer Notifier.
+ * Their implementation relays the asynchronous messages received from the
+ * network nodes to the the SAL Flow Programmer Notifier Service on the proper
+ * container.
+ */
+public interface IFlowProgrammerNotifier extends
+        IPluginOutFlowProgrammerService {
+
+}
index 45c0211787d837b7b7a40a02095d9cd1c8804140..26471a7f754247c9b68d7845550ee382aabfa3b5 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -15,6 +14,7 @@ import java.util.Hashtable;
 import org.apache.felix.dm.Component;
 import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketListen;
 import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketMux;
+import org.opendaylight.controller.protocol_plugin.openflow.IFlowProgrammerNotifier;
 import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
 import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimInternalListener;
 import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsManager;
@@ -23,12 +23,14 @@ import org.opendaylight.controller.protocol_plugin.openflow.IRefreshInternalProv
 import org.opendaylight.controller.protocol_plugin.openflow.IStatisticsListener;
 import org.opendaylight.controller.protocol_plugin.openflow.ITopologyServiceShimListener;
 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
 import org.opendaylight.controller.protocol_plugin.openflow.core.internal.Controller;
 import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
 import org.opendaylight.controller.sal.core.IContainerListener;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.discovery.IDiscoveryService;
 import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
+import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService;
 import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
 import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
 import org.opendaylight.controller.sal.packet.IPluginInDataPacketService;
@@ -42,92 +44,98 @@ import org.slf4j.LoggerFactory;
 
 /**
  * Openflow protocol plugin Activator
- *
- *
+ * 
+ * 
  */
 public class Activator extends ComponentActivatorAbstractBase {
     protected static final Logger logger = LoggerFactory
             .getLogger(Activator.class);
 
     /**
-     * Function called when the activator starts just after some
-     * initializations are done by the
-     * ComponentActivatorAbstractBase.
-     *
+     * Function called when the activator starts just after some initializations
+     * are done by the ComponentActivatorAbstractBase.
+     * 
      */
     public void init() {
     }
 
     /**
-     * Function called when the activator stops just before the
-     * cleanup done by ComponentActivatorAbstractBase
-     *
+     * Function called when the activator stops just before the cleanup done by
+     * ComponentActivatorAbstractBase
+     * 
      */
     public void destroy() {
     }
 
     /**
-     * Function that is used to communicate to dependency manager the
-     * list of known implementations for services inside a container
-     *
-     *
+     * Function that is used to communicate to dependency manager the list of
+     * known implementations for services inside a container
+     * 
+     * 
      * @return An array containing all the CLASS objects that will be
-     * instantiated in order to get an fully working implementation
-     * Object
+     *         instantiated in order to get an fully working implementation
+     *         Object
      */
     public Object[] getImplementations() {
         Object[] res = { TopologyServices.class, DataPacketServices.class,
-                InventoryService.class, ReadService.class };
+                InventoryService.class, ReadService.class,
+                FlowProgrammerNotifier.class };
         return res;
     }
 
     /**
-     * Function that is called when configuration of the dependencies
-     * is required.
-     *
-     * @param c dependency manager Component object, used for
-     * configuring the dependencies exported and imported
-     * @param imp Implementation class that is being configured,
-     * needed as long as the same routine can configure multiple
-     * implementations
-     * @param containerName The containerName being configured, this allow
-     * also optional per-container different behavior if needed, usually
-     * should not be the case though.
+     * Function that is called when configuration of the dependencies is
+     * required.
+     * 
+     * @param c
+     *            dependency manager Component object, used for configuring the
+     *            dependencies exported and imported
+     * @param imp
+     *            Implementation class that is being configured, needed as long
+     *            as the same routine can configure multiple implementations
+     * @param containerName
+     *            The containerName being configured, this allow also optional
+     *            per-container different behavior if needed, usually should not
+     *            be the case though.
      */
     public void configureInstance(Component c, Object imp, String containerName) {
         if (imp.equals(TopologyServices.class)) {
             // export the service to be used by SAL
-            c.setInterface(new String[] {
-                    IPluginInTopologyService.class.getName(),
-                    ITopologyServiceShimListener.class.getName() }, null);
+            c.setInterface(
+                    new String[] { IPluginInTopologyService.class.getName(),
+                            ITopologyServiceShimListener.class.getName() },
+                    null);
             // Hook the services coming in from SAL, as optional in
             // case SAL is not yet there, could happen
-            c.add(createContainerServiceDependency(containerName).setService(
-                    IPluginOutTopologyService.class).setCallbacks(
-                    "setPluginOutTopologyService",
-                    "unsetPluginOutTopologyService").setRequired(false));
-            c.add(createServiceDependency().setService(
-                    IRefreshInternalProvider.class).setCallbacks(
-                    "setRefreshInternalProvider",
-                    "unsetRefreshInternalProvider").setRequired(false));
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IPluginOutTopologyService.class)
+                    .setCallbacks("setPluginOutTopologyService",
+                            "unsetPluginOutTopologyService").setRequired(false));
+            c.add(createServiceDependency()
+                    .setService(IRefreshInternalProvider.class)
+                    .setCallbacks("setRefreshInternalProvider",
+                            "unsetRefreshInternalProvider").setRequired(false));
         }
 
         if (imp.equals(InventoryService.class)) {
             // export the service
-            c.setInterface(new String[] {
-                    IPluginInInventoryService.class.getName(),
-                    IStatisticsListener.class.getName(),
-                    IInventoryShimInternalListener.class.getName() }, null);
+            c.setInterface(
+                    new String[] { IPluginInInventoryService.class.getName(),
+                            IStatisticsListener.class.getName(),
+                            IInventoryShimInternalListener.class.getName() },
+                    null);
 
             // Now lets add a service dependency to make sure the
             // provider of service exists
-            c.add(createServiceDependency().setService(IController.class,
-                    "(name=Controller)").setCallbacks("setController",
-                    "unsetController").setRequired(true));
-            c.add(createContainerServiceDependency(containerName).setService(
-                    IPluginOutInventoryService.class).setCallbacks(
-                    "setPluginOutInventoryServices",
-                    "unsetPluginOutInventoryServices").setRequired(false));
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IPluginOutInventoryService.class)
+                    .setCallbacks("setPluginOutInventoryServices",
+                            "unsetPluginOutInventoryServices")
+                    .setRequired(false));
         }
 
         if (imp.equals(DataPacketServices.class)) {
@@ -139,17 +147,19 @@ public class Activator extends ComponentActivatorAbstractBase {
             c.setInterface(IPluginInDataPacketService.class.getName(), props);
             // Hook the services coming in from SAL, as optional in
             // case SAL is not yet there, could happen
-            c.add(createServiceDependency().setService(IController.class,
-                    "(name=Controller)").setCallbacks("setController",
-                    "unsetController").setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
             // This is required for the transmission to happen properly
             c.add(createServiceDependency().setService(IDataPacketMux.class)
                     .setCallbacks("setIDataPacketMux", "unsetIDataPacketMux")
                     .setRequired(true));
-            c.add(createContainerServiceDependency(containerName).setService(
-                    IPluginOutDataPacketService.class).setCallbacks(
-                    "setPluginOutDataPacketService",
-                    "unsetPluginOutDataPacketService").setRequired(false));
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IPluginOutDataPacketService.class)
+                    .setCallbacks("setPluginOutDataPacketService",
+                            "unsetPluginOutDataPacketService")
+                    .setRequired(false));
         }
 
         if (imp.equals(ReadService.class)) {
@@ -159,21 +169,36 @@ public class Activator extends ComponentActivatorAbstractBase {
             // by SAL
             props.put("protocolPluginType", Node.NodeIDType.OPENFLOW);
             c.setInterface(IPluginInReadService.class.getName(), props);
-            c.add(createServiceDependency().setService(
-                    IPluginReadServiceFilter.class).setCallbacks("setService",
-                    "unsetService").setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IPluginReadServiceFilter.class)
+                    .setCallbacks("setService", "unsetService")
+                    .setRequired(true));
+        }
+
+        if (imp.equals(FlowProgrammerNotifier.class)) {
+            // export the service to be used by SAL
+            Dictionary<String, Object> props = new Hashtable<String, Object>();
+            // Set the protocolPluginType property which will be used
+            // by SAL
+            props.put("protocolPluginType", Node.NodeIDType.OPENFLOW);
+            c.setInterface(IFlowProgrammerNotifier.class.getName(), props);
+
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IPluginOutFlowProgrammerService.class)
+                    .setCallbacks("setPluginOutFlowProgrammerService",
+                            "unsetPluginOutFlowProgrammerService")
+                    .setRequired(true));
         }
     }
 
     /**
-     * Function that is used to communicate to dependency manager the
-     * list of known implementations for services that are container
-     * independent.
-     *
-     *
+     * Function that is used to communicate to dependency manager the list of
+     * known implementations for services that are container independent.
+     * 
+     * 
      * @return An array containing all the CLASS objects that will be
-     * instantiated in order to get an fully working implementation
-     * Object
+     *         instantiated in order to get an fully working implementation
+     *         Object
      */
     public Object[] getGlobalImplementations() {
         Object[] res = { Controller.class, OFStatisticsManager.class,
@@ -184,14 +209,15 @@ public class Activator extends ComponentActivatorAbstractBase {
     }
 
     /**
-     * Function that is called when configuration of the dependencies
-     * is required.
-     *
-     * @param c dependency manager Component object, used for
-     * configuring the dependencies exported and imported
-     * @param imp Implementation class that is being configured,
-     * needed as long as the same routine can configure multiple
-     * implementations
+     * Function that is called when configuration of the dependencies is
+     * required.
+     * 
+     * @param c
+     *            dependency manager Component object, used for configuring the
+     *            dependencies exported and imported
+     * @param imp
+     *            Implementation class that is being configured, needed as long
+     *            as the same routine can configure multiple implementations
      */
     public void configureGlobalInstance(Component c, Object imp) {
 
@@ -208,26 +234,39 @@ public class Activator extends ComponentActivatorAbstractBase {
             // Set the protocolPluginType property which will be used
             // by SAL
             props.put("protocolPluginType", Node.NodeIDType.OPENFLOW);
-            c.setInterface(IPluginInFlowProgrammerService.class
-                           .getName(), props);
+            c.setInterface(
+                    new String[] {
+                            IPluginInFlowProgrammerService.class.getName(),
+                            IMessageListener.class.getName(),
+                            IContainerListener.class.getName() }, props);
+
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+
+            c.add(createServiceDependency()
+                    .setService(IFlowProgrammerNotifier.class)
+                    .setCallbacks("setFlowProgrammerNotifier",
+                            "unsetsetFlowProgrammerNotifier")
+                    .setRequired(false));
 
-            c.add(createServiceDependency().setService(IController.class,
-                    "(name=Controller)").setCallbacks("setController",
-                    "unsetController").setRequired(true));
         }
 
         if (imp.equals(ReadServiceFilter.class)) {
 
-            c.setInterface(new String[] {
-                    IPluginReadServiceFilter.class.getName(),
-                    IContainerListener.class.getName() }, null);
+            c.setInterface(
+                    new String[] { IPluginReadServiceFilter.class.getName(),
+                            IContainerListener.class.getName() }, null);
 
-            c.add(createServiceDependency().setService(IController.class,
-                    "(name=Controller)").setCallbacks("setController",
-                    "unsetController").setRequired(true));
-            c.add(createServiceDependency().setService(
-                    IOFStatisticsManager.class).setCallbacks("setService",
-                    "unsetService").setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IOFStatisticsManager.class)
+                    .setCallbacks("setService", "unsetService")
+                    .setRequired(true));
         }
 
         if (imp.equals(OFStatisticsManager.class)) {
@@ -235,34 +274,38 @@ public class Activator extends ComponentActivatorAbstractBase {
             c.setInterface(new String[] { IOFStatisticsManager.class.getName(),
                     IInventoryShimExternalListener.class.getName() }, null);
 
-            c.add(createServiceDependency().setService(IController.class,
-                    "(name=Controller)").setCallbacks("setController",
-                    "unsetController").setRequired(true));
-            c.add(createServiceDependency().setService(
-                       IStatisticsListener.class)
-                       .setCallbacks("setStatisticsListener",
-                    "unsetStatisticsListener").setRequired(false));
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IStatisticsListener.class)
+                    .setCallbacks("setStatisticsListener",
+                            "unsetStatisticsListener").setRequired(false));
         }
 
         if (imp.equals(DiscoveryService.class)) {
             // export the service
-            c.setInterface(new String[] {
-                    IInventoryShimExternalListener.class.getName(),
-                    IDataPacketListen.class.getName(),
-                    IContainerListener.class.getName() }, null);
-
-            c.add(createServiceDependency().setService(IController.class,
-                    "(name=Controller)").setCallbacks("setController",
-                    "unsetController").setRequired(true));
+            c.setInterface(
+                    new String[] {
+                            IInventoryShimExternalListener.class.getName(),
+                            IDataPacketListen.class.getName(),
+                            IContainerListener.class.getName() }, null);
+
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
             c.add(createContainerServiceDependency(
-                    GlobalConstants.DEFAULT.toString()).setService(
-                    IPluginInInventoryService.class).setCallbacks(
-                    "setPluginInInventoryService",
-                    "unsetPluginInInventoryService").setRequired(true));
+                    GlobalConstants.DEFAULT.toString())
+                    .setService(IPluginInInventoryService.class)
+                    .setCallbacks("setPluginInInventoryService",
+                            "unsetPluginInInventoryService").setRequired(true));
             c.add(createServiceDependency().setService(IDataPacketMux.class)
                     .setCallbacks("setIDataPacketMux", "unsetIDataPacketMux")
                     .setRequired(true));
-            c.add(createServiceDependency().setService(IDiscoveryService.class)
+            c.add(createServiceDependency()
+                    .setService(IDiscoveryService.class)
                     .setCallbacks("setDiscoveryService",
                             "unsetDiscoveryService").setRequired(true));
         }
@@ -274,15 +317,18 @@ public class Activator extends ComponentActivatorAbstractBase {
                     IContainerListener.class.getName(),
                     IInventoryShimExternalListener.class.getName() }, null);
 
-            c.add(createServiceDependency().setService(IController.class,
-                    "(name=Controller)").setCallbacks("setController",
-                    "unsetController").setRequired(true));
-            c.add(createServiceDependency().setService(
-                    IPluginOutDataPacketService.class).setCallbacks(
-                    "setPluginOutDataPacketService",
-                    "unsetPluginOutDataPacketService").setRequired(false));
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IPluginOutDataPacketService.class)
+                    .setCallbacks("setPluginOutDataPacketService",
+                            "unsetPluginOutDataPacketService")
+                    .setRequired(false));
             // See if there is any local packet dispatcher
-            c.add(createServiceDependency().setService(IDataPacketListen.class)
+            c.add(createServiceDependency()
+                    .setService(IDataPacketListen.class)
                     .setCallbacks("setIDataPacketListen",
                             "unsetIDataPacketListen").setRequired(false));
         }
@@ -291,31 +337,35 @@ public class Activator extends ComponentActivatorAbstractBase {
             c.setInterface(new String[] { IContainerListener.class.getName() },
                     null);
 
-            c.add(createServiceDependency().setService(IController.class,
-                    "(name=Controller)").setCallbacks("setController",
-                    "unsetController").setRequired(true));
-            c.add(createServiceDependency().setService(
-                    IInventoryShimInternalListener.class).setCallbacks(
-                    "setInventoryShimInternalListener",
-                    "unsetInventoryShimInternalListener").setRequired(true));
-            c.add(createServiceDependency().setService(
-                    IInventoryShimExternalListener.class).setCallbacks(
-                    "setInventoryShimExternalListener",
-                    "unsetInventoryShimExternalListener").setRequired(false));
+            c.add(createServiceDependency()
+                    .setService(IController.class, "(name=Controller)")
+                    .setCallbacks("setController", "unsetController")
+                    .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IInventoryShimInternalListener.class)
+                    .setCallbacks("setInventoryShimInternalListener",
+                            "unsetInventoryShimInternalListener")
+                    .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IInventoryShimExternalListener.class)
+                    .setCallbacks("setInventoryShimExternalListener",
+                            "unsetInventoryShimExternalListener")
+                    .setRequired(false));
         }
 
         if (imp.equals(TopologyServiceShim.class)) {
             c.setInterface(new String[] { IDiscoveryService.class.getName(),
                     IContainerListener.class.getName(),
                     IRefreshInternalProvider.class.getName() }, null);
-            c.add(createServiceDependency().setService(
-                    ITopologyServiceShimListener.class).setCallbacks(
-                    "setTopologyServiceShimListener",
-                    "unsetTopologyServiceShimListener").setRequired(true));
-            c.add(createServiceDependency().setService(
-                    IOFStatisticsManager.class).setCallbacks(
-                    "setStatisticsManager", "unsetStatisticsManager")
-                    .setRequired(false));
+            c.add(createServiceDependency()
+                    .setService(ITopologyServiceShimListener.class)
+                    .setCallbacks("setTopologyServiceShimListener",
+                            "unsetTopologyServiceShimListener")
+                    .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(IOFStatisticsManager.class)
+                    .setCallbacks("setStatisticsManager",
+                            "unsetStatisticsManager").setRequired(false));
         }
     }
 }
index 7e89cd0a42658a50d5579dd21649266d99ff6ab1..47ce283331c0bbe6b29fe6a231761656fdcb7728 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -71,9 +70,6 @@ import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
 
 /**
  * Utility class for converting a SAL Flow into the OF flow and vice-versa
- *
- *
- *
  */
 public class FlowConverter {
     private Flow flow; // SAL Flow
@@ -99,8 +95,9 @@ public class FlowConverter {
     }
 
     /**
-     * Returns the match in OF 1.0 (OFMatch) form or OF 1.0 + IPv6 extensions form (V6Match)
-     *
+     * Returns the match in OF 1.0 (OFMatch) form or OF 1.0 + IPv6 extensions
+     * form (V6Match)
+     * 
      * @return
      */
     public OFMatch getOFMatch() {
@@ -173,11 +170,11 @@ public class FlowConverter {
             }
             if (match.isPresent(MatchType.NW_TOS)) {
                 /*
-                 *  OF 1.0 switch expects the TOS as the 6 msb in the byte.
-                 *  it is actually the DSCP field followed by a zero ECN
+                 * OF 1.0 switch expects the TOS as the 6 msb in the byte. it is
+                 * actually the DSCP field followed by a zero ECN
                  */
                 byte tos = (Byte) match.getField(MatchType.NW_TOS).getValue();
-                byte dscp = (byte)((int)tos << 2);
+                byte dscp = (byte) ((int) tos << 2);
                 if (!isIPv6) {
                     ofMatch.setNetworkTypeOfService(dscp);
                     wildcards &= ~OFMatch.OFPFW_NW_TOS;
@@ -261,6 +258,7 @@ public class FlowConverter {
 
     /**
      * Returns the list of actions in OF 1.0 form
+     * 
      * @return
      */
     public List<OFAction> getOFActions() {
@@ -303,7 +301,8 @@ public class FlowConverter {
                 if (action.getType() == ActionType.CONTROLLER) {
                     OFActionOutput ofAction = new OFActionOutput();
                     ofAction.setPort(OFPort.OFPP_CONTROLLER.getValue());
-                    // We want the whole frame hitting the match be sent to the controller
+                    // We want the whole frame hitting the match be sent to the
+                    // controller
                     ofAction.setMaxLength((short) 0xffff);
                     actionsList.add(ofAction);
                     actionsLength += OFActionOutput.MINIMUM_LENGTH;
@@ -408,7 +407,7 @@ public class FlowConverter {
                     continue;
                 }
                 if (action.getType() == ActionType.SET_NEXT_HOP) {
-                    //TODO
+                    // TODO
                     continue;
                 }
             }
@@ -417,9 +416,9 @@ public class FlowConverter {
     }
 
     /**
-     * Utility to convert a SAL flow to an OF 1.0 (OFFlowMod) or
-     * to an OF 1.0 + IPv6 extension (V6FlowMod) Flow modifier Message
-     *
+     * Utility to convert a SAL flow to an OF 1.0 (OFFlowMod) or to an OF 1.0 +
+     * IPv6 extension (V6FlowMod) Flow modifier Message
+     * 
      * @param sw
      * @param command
      * @param port
@@ -447,6 +446,14 @@ public class FlowConverter {
             if (port != null) {
                 ((OFFlowMod) fm).setOutPort(port);
             }
+            if (command == OFFlowMod.OFPFC_ADD
+                    || command == OFFlowMod.OFPFC_MODIFY
+                    || command == OFFlowMod.OFPFC_MODIFY_STRICT) {
+                if (flow.getIdleTimeout() != 0 || flow.getHardTimeout() != 0) {
+                    // Instruct switch to let controller know when flow expires
+                    ((OFFlowMod) fm).setFlags((short) 1);
+                }
+            }
         } else {
             ((V6FlowMod) fm).setVendor();
             ((V6FlowMod) fm).setMatch((V6Match) ofMatch);
@@ -463,6 +470,14 @@ public class FlowConverter {
             if (port != null) {
                 ((V6FlowMod) fm).setOutPort(port);
             }
+            if (command == OFFlowMod.OFPFC_ADD
+                    || command == OFFlowMod.OFPFC_MODIFY
+                    || command == OFFlowMod.OFPFC_MODIFY_STRICT) {
+                if (flow.getIdleTimeout() != 0 || flow.getHardTimeout() != 0) {
+                    // Instruct switch to let controller know when flow expires
+                    ((V6FlowMod) fm).setFlags((short) 1);
+                }
+            }
         }
         return fm;
     }
@@ -472,8 +487,8 @@ public class FlowConverter {
             Match salMatch = new Match();
 
             /*
-             * Installed flow may not have a Match defined
-             * like in case of a drop all flow
+             * Installed flow may not have a Match defined like in case of a
+             * drop all flow
              */
             if (ofMatch != null) {
                 if (!isIPv6) {
@@ -512,38 +527,35 @@ public class FlowConverter {
                     if (ofMatch.getNetworkSource() != 0) {
                         salMatch.setField(MatchType.NW_SRC, NetUtils
                                 .getInetAddress(ofMatch.getNetworkSource()),
-                                NetUtils.getInetNetworkMask(ofMatch
-                                        .getNetworkSourceMaskLen(), false));
+                                NetUtils.getInetNetworkMask(
+                                        ofMatch.getNetworkSourceMaskLen(),
+                                        false));
                     }
                     if (ofMatch.getNetworkDestination() != 0) {
-                        salMatch
-                                .setField(
-                                        MatchType.NW_DST,
-                                        NetUtils.getInetAddress(ofMatch
-                                                .getNetworkDestination()),
-                                        NetUtils
-                                                .getInetNetworkMask(
-                                                        ofMatch
-                                                                .getNetworkDestinationMaskLen(),
-                                                        false));
+                        salMatch.setField(MatchType.NW_DST,
+                                NetUtils.getInetAddress(ofMatch
+                                        .getNetworkDestination()),
+                                NetUtils.getInetNetworkMask(
+                                        ofMatch.getNetworkDestinationMaskLen(),
+                                        false));
                     }
                     if (ofMatch.getNetworkTypeOfService() != 0) {
-                       int dscp = NetUtils.getUnsignedByte(
-                                       ofMatch.getNetworkTypeOfService());
-                       byte tos = (byte)(dscp >> 2);
+                        int dscp = NetUtils.getUnsignedByte(ofMatch
+                                .getNetworkTypeOfService());
+                        byte tos = (byte) (dscp >> 2);
                         salMatch.setField(MatchType.NW_TOS, tos);
                     }
                     if (ofMatch.getNetworkProtocol() != 0) {
-                        salMatch.setField(MatchType.NW_PROTO, ofMatch
-                                .getNetworkProtocol());
+                        salMatch.setField(MatchType.NW_PROTO,
+                                ofMatch.getNetworkProtocol());
                     }
                     if (ofMatch.getTransportSource() != 0) {
-                        salMatch.setField(MatchType.TP_SRC, ((Short) ofMatch
-                                .getTransportSource()));
+                        salMatch.setField(MatchType.TP_SRC,
+                                ((Short) ofMatch.getTransportSource()));
                     }
                     if (ofMatch.getTransportDestination() != 0) {
-                        salMatch.setField(MatchType.TP_DST, ((Short) ofMatch
-                                .getTransportDestination()));
+                        salMatch.setField(MatchType.TP_DST,
+                                ((Short) ofMatch.getTransportDestination()));
                     }
                 } else {
                     // Compute OF1.0 + IPv6 extensions Match
@@ -581,32 +593,32 @@ public class FlowConverter {
                                 .getDataLayerVirtualLanPriorityCodePoint());
                     }
                     if (v6Match.getNetworkSrc() != null) {
-                        salMatch.setField(MatchType.NW_SRC, v6Match
-                                .getNetworkSrc(), v6Match
-                                .getNetworkSourceMask());
+                        salMatch.setField(MatchType.NW_SRC,
+                                v6Match.getNetworkSrc(),
+                                v6Match.getNetworkSourceMask());
                     }
                     if (v6Match.getNetworkDest() != null) {
-                        salMatch.setField(MatchType.NW_DST, v6Match
-                                .getNetworkDest(), v6Match
-                                .getNetworkDestinationMask());
+                        salMatch.setField(MatchType.NW_DST,
+                                v6Match.getNetworkDest(),
+                                v6Match.getNetworkDestinationMask());
                     }
                     if (v6Match.getNetworkTypeOfService() != 0) {
-                       int dscp = NetUtils.getUnsignedByte(
-                                       v6Match.getNetworkTypeOfService());
-                       byte tos = (byte) (dscp >> 2);
+                        int dscp = NetUtils.getUnsignedByte(v6Match
+                                .getNetworkTypeOfService());
+                        byte tos = (byte) (dscp >> 2);
                         salMatch.setField(MatchType.NW_TOS, tos);
                     }
                     if (v6Match.getNetworkProtocol() != 0) {
-                        salMatch.setField(MatchType.NW_PROTO, v6Match
-                                .getNetworkProtocol());
+                        salMatch.setField(MatchType.NW_PROTO,
+                                v6Match.getNetworkProtocol());
                     }
                     if (v6Match.getTransportSource() != 0) {
-                        salMatch.setField(MatchType.TP_SRC, ((Short) v6Match
-                                .getTransportSource()));
+                        salMatch.setField(MatchType.TP_SRC,
+                                ((Short) v6Match.getTransportSource()));
                     }
                     if (v6Match.getTransportDestination() != 0) {
-                        salMatch.setField(MatchType.TP_DST, ((Short) v6Match
-                                .getTransportDestination()));
+                        salMatch.setField(MatchType.TP_DST,
+                                ((Short) v6Match.getTransportDestination()));
                     }
                 }
             }
@@ -635,10 +647,12 @@ public class FlowConverter {
                         } else if (ofPort == OFPort.OFPP_NORMAL.getValue()) {
                             salAction = new HwPath();
                         } else if (ofPort == OFPort.OFPP_TABLE.getValue()) {
-                            salAction = new HwPath(); //TODO: we do not handle table in sal for now
+                            salAction = new HwPath(); // TODO: we do not handle
+                                                      // table in sal for now
                         } else {
-                            salAction = new Output(NodeConnectorCreator
-                                    .createOFNodeConnector(ofPort, node));
+                            salAction = new Output(
+                                    NodeConnectorCreator.createOFNodeConnector(
+                                            ofPort, node));
                         }
                     } else if (ofAction instanceof OFActionVirtualLanIdentifier) {
                         salAction = new SetVlanId(
diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerNotifier.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerNotifier.java
new file mode 100644 (file)
index 0000000..594164d
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.protocol_plugin.openflow.internal;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.protocol_plugin.openflow.IFlowProgrammerNotifier;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Flow Programmer Notifier class for relaying asynchronous messages received
+ * from the network node to the listeners on the proper container
+ */
+public class FlowProgrammerNotifier implements IFlowProgrammerNotifier {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(FlowProgrammerNotifier.class);
+    private IPluginOutFlowProgrammerService salNotifier;
+
+    public FlowProgrammerNotifier() {
+        salNotifier = null;
+    }
+
+    void init(Component c) {
+        logger.debug("INIT called!");
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     * 
+     */
+    void destroy() {
+        logger.debug("DESTROY called!");
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     * 
+     */
+    void start() {
+        logger.debug("START called!");
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     * 
+     */
+    void stop() {
+        logger.debug("STOP called!");
+    }
+
+    public void setPluginOutFlowProgrammerService(
+            IPluginOutFlowProgrammerService s) {
+        this.salNotifier = s;
+    }
+
+    public void unsetPluginOutFlowProgrammerService(
+            IPluginOutFlowProgrammerService s) {
+        if (this.salNotifier == s) {
+            this.salNotifier = null;
+        }
+    }
+
+    @Override
+    public void flowRemoved(Node node, Flow flow) {
+        if (salNotifier != null) {
+            salNotifier.flowRemoved(node, flow);
+        } else {
+            logger.warn("Unable to relay switch message to upper layer");
+        }
+    }
+
+}
index 983c7c2190e09d19298f7454a093615956f91299..2926c22c43f43d4c903157a4f09a1a6758c422a1 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
 package org.opendaylight.controller.protocol_plugin.openflow.internal;
 
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.protocol_plugin.openflow.IFlowProgrammerNotifier;
 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
+import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
 import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Error;
 import org.openflow.protocol.OFError;
 import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFFlowRemoved;
 import org.openflow.protocol.OFMessage;
 import org.openflow.protocol.OFPort;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.action.OFAction;
 
+import org.opendaylight.controller.sal.core.ContainerFlow;
+import org.opendaylight.controller.sal.core.IContainerListener;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.Node.NodeIDType;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.UpdateType;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
+import org.opendaylight.controller.sal.match.Match;
+import org.opendaylight.controller.sal.match.MatchType;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.NodeCreator;
 import org.opendaylight.controller.sal.utils.StatusCode;
 import org.opendaylight.controller.sal.utils.Status;
 import org.slf4j.Logger;
@@ -29,18 +48,19 @@ import org.slf4j.LoggerFactory;
 
 /**
  * Represents the openflow plugin component in charge of programming the flows
- * on the switch. It servers the install requests coming from the SAL layer.
- *
- *
- *
+ * the flow programming and relay them to functional modules above SAL.
  */
-public class FlowProgrammerService implements IPluginInFlowProgrammerService {
-       private static final Logger log = LoggerFactory
-    .getLogger(FlowProgrammerService.class);
+public class FlowProgrammerService implements IPluginInFlowProgrammerService,
+        IMessageListener, IContainerListener {
+    private static final Logger log = LoggerFactory
+            .getLogger(FlowProgrammerService.class);
     private IController controller;
+    private ConcurrentMap<String, IFlowProgrammerNotifier> flowProgrammerNotifiers;
+    private Map<String, Set<NodeConnector>> containerToNc;
 
     public FlowProgrammerService() {
         controller = null;
+        flowProgrammerNotifiers = new ConcurrentHashMap<String, IFlowProgrammerNotifier>();
     }
 
     public void setController(IController core) {
@@ -53,37 +73,61 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService {
         }
     }
 
+    public void setFlowProgrammerNotifier(Map<String, ?> props,
+            IFlowProgrammerNotifier s) {
+        if (props == null || props.get("containerName") == null) {
+            log.error("Didn't receive the service correct properties");
+            return;
+        }
+        String containerName = (String) props.get("containerName");
+        this.flowProgrammerNotifiers.put(containerName, s);
+    }
+
+    public void unsetFlowProgrammerNotifier(Map<String, ?> props,
+            IFlowProgrammerNotifier s) {
+        if (props == null || props.get("containerName") == null) {
+            log.error("Didn't receive the service correct properties");
+            return;
+        }
+        String containerName = (String) props.get("containerName");
+        if (this.flowProgrammerNotifiers != null
+                && this.flowProgrammerNotifiers.containsKey(containerName)
+                && this.flowProgrammerNotifiers.get(containerName) == s) {
+            this.flowProgrammerNotifiers.remove(containerName);
+        }
+    }
+
     /**
      * Function called by the dependency manager when all the required
      * dependencies are satisfied
-     *
+     * 
      */
     void init() {
+        this.controller.addMessageListener(OFType.FLOW_REMOVED, this);
     }
 
     /**
-     * Function called by the dependency manager when at least one
-     * dependency become unsatisfied or when the component is shutting
-     * down because for example bundle is being stopped.
-     *
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     * 
      */
     void destroy() {
     }
 
     /**
-     * Function called by dependency manager after "init ()" is called
-     * and after the services provided by the class are registered in
-     * the service registry
-     *
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     * 
      */
     void start() {
     }
 
     /**
-     * Function called by the dependency manager before the services
-     * exported by the component are unregistered, this will be
-     * followed by a "destroy ()" calls
-     *
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     * 
      */
     void stop() {
     }
@@ -92,8 +136,8 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService {
     public Status addFlow(Node node, Flow flow) {
         String action = "add";
         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
-            return new Status(StatusCode.NOTACCEPTABLE,
-                    errorString("send", action, "Invalid node type"));
+            return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
+                    action, "Invalid node type"));
         }
 
         if (controller != null) {
@@ -107,53 +151,52 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService {
                  */
                 Object result = sw.syncSend(msg);
                 if (result instanceof Boolean) {
-                    return ((Boolean) result == Boolean.TRUE) ?
-                            new Status(StatusCode.SUCCESS, null)
-                            : new Status(StatusCode.TIMEOUT,
-                                    errorString(null, action,
-                                            "Request Timed Out"));
+                    return ((Boolean) result == Boolean.TRUE) ? new Status(
+                            StatusCode.SUCCESS, null) : new Status(
+                            StatusCode.TIMEOUT, errorString(null, action,
+                                    "Request Timed Out"));
                 } else if (result instanceof OFError) {
-                       OFError res = (OFError) result;
-                       if (res.getErrorType() == V6Error.NICIRA_VENDOR_ERRORTYPE) {
-                               V6Error er = new V6Error(res);
-                               byte[] b = res.getError();
-                               ByteBuffer bb = ByteBuffer.allocate(b.length);
-                               bb.put(b);
-                               bb.rewind();
-                               er.readFrom(bb);
-                               log.trace("V6Error {}",er);
-                               return new Status(StatusCode.INTERNALERROR,
-                                errorString("program", action, "Vendor Extension Internal Error"));
-                       }
-                    return new Status(StatusCode.INTERNALERROR,
-                            errorString("program", action, Utils
-                            .getOFErrorString(res)));
+                    OFError res = (OFError) result;
+                    if (res.getErrorType() == V6Error.NICIRA_VENDOR_ERRORTYPE) {
+                        V6Error er = new V6Error(res);
+                        byte[] b = res.getError();
+                        ByteBuffer bb = ByteBuffer.allocate(b.length);
+                        bb.put(b);
+                        bb.rewind();
+                        er.readFrom(bb);
+                        return new Status(StatusCode.INTERNALERROR,
+                                errorString("program", action,
+                                        "Vendor Extension Internal Error"));
+                    }
+                    return new Status(StatusCode.INTERNALERROR, errorString(
+                            "program", action, Utils.getOFErrorString(res)));
                 } else {
-                    return new Status(StatusCode.INTERNALERROR,
-                            errorString("send", action, "Internal Error"));
+                    return new Status(StatusCode.INTERNALERROR, errorString(
+                            "send", action, "Internal Error"));
                 }
             } else {
                 return new Status(StatusCode.GONE, errorString("send", action,
-                                "Switch is not available"));
+                        "Switch is not available"));
             }
         }
-        return new Status(StatusCode.INTERNALERROR,
-                errorString("send", action, "Internal plugin error"));
+        return new Status(StatusCode.INTERNALERROR, errorString("send", action,
+                "Internal plugin error"));
     }
 
     @Override
     public Status modifyFlow(Node node, Flow oldFlow, Flow newFlow) {
         String action = "modify";
         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
-            return new Status(StatusCode.NOTACCEPTABLE,
-                    errorString("send", action, "Invalid node type"));
+            return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
+                    action, "Invalid node type"));
         }
         if (controller != null) {
             ISwitch sw = controller.getSwitch((Long) node.getID());
             if (sw != null) {
                 OFMessage msg1 = null, msg2 = null;
 
-                // If priority and match portion are the same, send a modification message
+                // If priority and match portion are the same, send a
+                // modification message
                 if (oldFlow.getPriority() != newFlow.getPriority()
                         || !oldFlow.getMatch().equals(newFlow.getMatch())) {
                     msg1 = new FlowConverter(oldFlow).getOFFlowMod(
@@ -171,34 +214,32 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService {
                 Object result = sw.syncSend(msg1);
                 if (result instanceof Boolean) {
                     if ((Boolean) result == Boolean.FALSE) {
-                        return new Status(StatusCode.TIMEOUT,
-                                errorString(null, action,
-                                        "Request Timed Out"));
+                        return new Status(StatusCode.TIMEOUT, errorString(null,
+                                action, "Request Timed Out"));
                     } else if (msg2 == null) {
                         return new Status(StatusCode.SUCCESS, null);
                     }
                 } else if (result instanceof OFError) {
-                    return new Status(StatusCode.INTERNALERROR,
-                            errorString("program", action, Utils
-                            .getOFErrorString((OFError) result)));
+                    return new Status(StatusCode.INTERNALERROR, errorString(
+                            "program", action,
+                            Utils.getOFErrorString((OFError) result)));
                 } else {
-                    return new Status(StatusCode.INTERNALERROR,
-                            errorString("send", action, "Internal Error"));
+                    return new Status(StatusCode.INTERNALERROR, errorString(
+                            "send", action, "Internal Error"));
                 }
 
                 if (msg2 != null) {
                     action = "add";
                     result = sw.syncSend(msg2);
                     if (result instanceof Boolean) {
-                        return ((Boolean) result == Boolean.TRUE) ?
-                                new Status(StatusCode.SUCCESS, null)
-                                : new Status(StatusCode.TIMEOUT,
-                                        errorString(null, action,
-                                                "Request Timed Out"));
+                        return ((Boolean) result == Boolean.TRUE) ? new Status(
+                                StatusCode.SUCCESS, null) : new Status(
+                                StatusCode.TIMEOUT, errorString(null, action,
+                                        "Request Timed Out"));
                     } else if (result instanceof OFError) {
                         return new Status(StatusCode.INTERNALERROR,
                                 errorString("program", action, Utils
-                                .getOFErrorString((OFError) result)));
+                                        .getOFErrorString((OFError) result)));
                     } else {
                         return new Status(StatusCode.INTERNALERROR,
                                 errorString("send", action, "Internal Error"));
@@ -209,16 +250,16 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService {
                         "Switch is not available"));
             }
         }
-        return new Status(StatusCode.INTERNALERROR,
-                errorString("send", action, "Internal plugin error"));
+        return new Status(StatusCode.INTERNALERROR, errorString("send", action,
+                "Internal plugin error"));
     }
 
     @Override
     public Status removeFlow(Node node, Flow flow) {
         String action = "remove";
         if (!node.getType().equals(NodeIDType.OPENFLOW)) {
-            return new Status(StatusCode.NOTACCEPTABLE,
-                    errorString("send", action, "Invalid node type"));
+            return new Status(StatusCode.NOTACCEPTABLE, errorString("send",
+                    action, "Invalid node type"));
         }
         if (controller != null) {
             ISwitch sw = controller.getSwitch((Long) node.getID());
@@ -227,26 +268,25 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService {
                         OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE);
                 Object result = sw.syncSend(msg);
                 if (result instanceof Boolean) {
-                    return ((Boolean) result == Boolean.TRUE) ?
-                            new Status(StatusCode.SUCCESS, null)
-                            : new Status(StatusCode.TIMEOUT,
-                                    errorString(null, action,
-                                            "Request Timed Out"));
+                    return ((Boolean) result == Boolean.TRUE) ? new Status(
+                            StatusCode.SUCCESS, null) : new Status(
+                            StatusCode.TIMEOUT, errorString(null, action,
+                                    "Request Timed Out"));
                 } else if (result instanceof OFError) {
-                    return new Status(StatusCode.INTERNALERROR,
-                            errorString("program", action, Utils
-                            .getOFErrorString((OFError) result)));
+                    return new Status(StatusCode.INTERNALERROR, errorString(
+                            "program", action,
+                            Utils.getOFErrorString((OFError) result)));
                 } else {
-                    return new Status(StatusCode.INTERNALERROR,
-                            errorString("send", action, "Internal Error"));
+                    return new Status(StatusCode.INTERNALERROR, errorString(
+                            "send", action, "Internal Error"));
                 }
             } else {
-                return new Status(StatusCode.GONE,  errorString("send", action,
+                return new Status(StatusCode.GONE, errorString("send", action,
                         "Switch is not available"));
             }
         }
-        return new Status(StatusCode.INTERNALERROR,
-                errorString("send", action, "Internal plugin error"));
+        return new Status(StatusCode.INTERNALERROR, errorString("send", action,
+                "Internal plugin error"));
     }
 
     @Override
@@ -260,4 +300,82 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService {
                         + " flow message: " : action + " the flow: ") + cause;
     }
 
+    @Override
+    public void receive(ISwitch sw, OFMessage msg) {
+        if (msg instanceof OFFlowRemoved) {
+            handleFlowRemovedMessage(sw, (OFFlowRemoved) msg);
+        }
+    }
+
+    private void handleFlowRemovedMessage(ISwitch sw, OFFlowRemoved msg) {
+        Node node = NodeCreator.createOFNode(sw.getId());
+        Flow flow = new FlowConverter(msg.getMatch(),
+                new ArrayList<OFAction>(0)).getFlow(node);
+        flow.setPriority(msg.getPriority());
+        flow.setIdleTimeout(msg.getIdleTimeout());
+        flow.setId(msg.getCookie());
+
+        Match match = flow.getMatch();
+        NodeConnector inPort = match.isPresent(MatchType.IN_PORT) ? (NodeConnector) match
+                .getField(MatchType.IN_PORT).getValue() : null;
+
+        for (Map.Entry<String, IFlowProgrammerNotifier> containerNotifier : flowProgrammerNotifiers
+                .entrySet()) {
+            String container = containerNotifier.getKey();
+            IFlowProgrammerNotifier notifier = containerNotifier.getValue();
+            /*
+             * Switch only provide us with the match information. For now let's
+             * try to identify the container membership only from the input port
+             * match field. In any case, upper layer consumers can derive
+             * whether the notification was not for them. More sophisticated
+             * filtering can be added later on.
+             */
+            if (inPort == null
+                    || container.equals(GlobalConstants.DEFAULT.toString())
+                    || this.containerToNc.get(container).contains(inPort)) {
+                notifier.flowRemoved(node, flow);
+            }
+        }
+    }
+
+    @Override
+    public void tagUpdated(String containerName, Node n, short oldTag,
+            short newTag, UpdateType t) {
+
+    }
+
+    @Override
+    public void containerFlowUpdated(String containerName,
+            ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) {
+    }
+
+    @Override
+    public void nodeConnectorUpdated(String containerName, NodeConnector p,
+            UpdateType type) {
+        Set<NodeConnector> target = null;
+
+        switch (type) {
+        case ADDED:
+            if (!containerToNc.containsKey(containerName)) {
+                containerToNc.put(containerName, new HashSet<NodeConnector>());
+            }
+            containerToNc.get(containerName).add(p);
+            break;
+        case CHANGED:
+            break;
+        case REMOVED:
+            target = containerToNc.get(containerName);
+            if (target != null) {
+                target.remove(p);
+            }
+            break;
+        default:
+        }
+
+    }
+
+    @Override
+    public void containerModeUpdated(UpdateType t) {
+
+    }
 }
index bc61f3b071b8c04718a6e4add3b15901bfb69e1c..73dcea574a41bb55b5fc653b5f4036c9cb81799b 100644 (file)
@@ -137,7 +137,7 @@ public class OFStatisticsManager implements IOFStatisticsManager,
                     .getLast());
             long timePeriod = (long) (factoredSamples * portStatsPeriod)
                     / (long) tickPeriod;
-            average = (8 * increment) / timePeriod;
+            average = (8L * increment) / timePeriod;
             return average;
         }
     }
index 47bb2213aaafcee053a7e6b083798ef57738ac4a..888d2e63ed745adc915d8ec45880e4d08ce276f9 100644 (file)
@@ -13,6 +13,7 @@ import java.nio.ByteBuffer;
 import java.util.LinkedList;
 import java.util.List;
 
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
 import org.openflow.protocol.OFPacketOut;
 import org.openflow.protocol.OFPort;
 import org.openflow.protocol.OFVendor;
@@ -20,8 +21,6 @@ import org.openflow.protocol.action.OFAction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
-
 /**
  * This class is used to create IPv6 Vendor Extension messages. Specfically, It
  * defines the methods used in creation of Vendor specific IPv6 Flow Mod message.
@@ -148,6 +147,22 @@ public class V6FlowMod extends OFVendor implements Cloneable {
         super.setVendor(V6StatsRequest.NICIRA_VENDOR_ID);
     }
     
+    /**
+     * Get flags
+     * @return
+     */
+    public short getFlags() {
+        return flags;
+    }
+
+    /**
+     * Set flags
+     * @param flags
+     */
+    public void setFlags(short flags) {
+        this.flags = flags;
+    }
+    
     /**
      * This method forms the Vendor extension IPv6 Flow Mod message.It uses the
      * fields in V6FlowMod class, and writes the data according to vendor 
@@ -167,7 +182,7 @@ public class V6FlowMod extends OFVendor implements Cloneable {
         data.putShort(this.priority);
         data.putInt(OFPacketOut.BUFFER_ID_NONE);
         data.putShort(outPort); /* output_port */
-        data.putShort((short) 0); /* flags */
+        data.putShort(flags); /* flags */
         match_len = this.match.getIPv6MatchLen();
         data.putShort(match_len);
         byte[] pad = new byte[6];
index cabe5712589a93f63f7310172bbc549629eae67b..8f6cfa42512642ba6e1115332c68898bb35ece75 100644 (file)
@@ -18,7 +18,7 @@ import org.opendaylight.controller.sal.utils.Status;
  * Interface for applications which maintain an authorization
  * database for their resources. Respective application web bundle
  * and User Manager make use of this interface to retrieve
- * authorization information at user or and role level
+ * authorization information at user or and role level.
  */
 public interface IResourceAuthorization {
 
@@ -90,15 +90,27 @@ public interface IResourceAuthorization {
     public List<String> getResourceGroups();
 
     /**
-     * Assign a resource group to a user group (role)
+     * Assign a resource group to a role
      *
-     * @param groupName the object expressing the resource group name and the access privilege
-     * @param role the user group (role) name
+     * @param groupName the name of the resource group
+     * @param privilege the access privilege role will have on the resource group
+     * @param role the role name
      * @return the status of the request
      */
+    @Deprecated
     public Status assignResourceGroupToRole(String groupName,
             Privilege privilege, String role);
 
+    /**
+     * Assign a resource group to a role. The access privilege on the resources
+     * is inferred by the AppRoleLevel associated to role.
+     *
+     * @param groupName the name of the resource group
+     * @param role the role name
+     * @return the status of the request
+     */
+    public Status assignResourceGroupToRole(String groupName, String role);
+    
     /**
      * Unassign the passed resource group from the specified role
      * 
diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerListener.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerListener.java
new file mode 100644 (file)
index 0000000..c66a3de
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.flowprogrammer;
+
+/**
+ * This interface defines the methods the SAL service which relay to the
+ * functional modules the asynchronous messages related to flow programming
+ * coming from the network nodes.
+ */
+public interface IFlowProgrammerListener extends
+        IPluginOutFlowProgrammerService {
+
+}
index 956942c09c6d6e3350fb857e16b3145881742d74..69972d67768fdcec042ac27f646f670c513561bd 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -13,15 +12,13 @@ import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.utils.Status;
 
 /**
- * Interface for installing/removing flows on a network node
- *
- *
- *
+ * Interface that defines the methods available to the functional modules above
+ * SAL for installing/modifying/removing flows on a network node
  */
 public interface IFlowProgrammerService {
     /**
      * Add a flow to the network node
-     *
+     * 
      * @param node
      * @param flow
      */
@@ -29,7 +26,7 @@ public interface IFlowProgrammerService {
 
     /**
      * Modify existing flow on the switch
-     *
+     * 
      * @param node
      * @param flow
      */
@@ -37,6 +34,7 @@ public interface IFlowProgrammerService {
 
     /**
      * Remove the flow from the network node
+     * 
      * @param node
      * @param flow
      */
@@ -44,6 +42,7 @@ public interface IFlowProgrammerService {
 
     /**
      * Remove all flows present on the network node
+     * 
      * @param node
      */
     Status removeAllFlows(Node node);
index 1fb99e0ab99bc4317184d1b077b0be8d0b69bb1b..79924fc3ddb25bc1891262bb351324ffacd568ac 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -13,40 +12,39 @@ import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.utils.Status;
 
 /**
- * @file   IPluginOutFlowProgrammer.java
- *
- * @brief  Flow programmer interface to be implemented by protocol plugins
- *
- *
- *
+ * @file IPluginOutFlowProgrammer.java
+ * 
+ * @brief Flow programmer interface to be implemented by protocol plugins
  */
 public interface IPluginInFlowProgrammerService {
     /**
      * Add a flow to the network node
-     *
+     * 
      * @param node
      * @param flow
      */
-       Status addFlow(Node node, Flow flow);
+    Status addFlow(Node node, Flow flow);
 
     /**
      * Modify existing flow on the switch
-     *
+     * 
      * @param node
      * @param flow
      */
-       Status modifyFlow(Node node, Flow oldFlow, Flow newFlow);
+    Status modifyFlow(Node node, Flow oldFlow, Flow newFlow);
 
     /**
      * Remove the flow from the network node
+     * 
      * @param node
      * @param flow
      */
-       Status removeFlow(Node node, Flow flow);
+    Status removeFlow(Node node, Flow flow);
 
     /**
      * Remove all flows present on the network node
+     * 
      * @param node
      */
-       Status removeAllFlows(Node node);
+    Status removeAllFlows(Node node);
 }
diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginOutFlowProgrammerService.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginOutFlowProgrammerService.java
new file mode 100644 (file)
index 0000000..2836f77
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.flowprogrammer;
+
+import org.opendaylight.controller.sal.core.Node;
+
+/**
+ * This interface defines the methods the protocol plugin must implement to
+ * inform the SAL layer about the asynchronous messages related to flow
+ * programming coming from the network nodes.
+ */
+public interface IPluginOutFlowProgrammerService {
+    /**
+     * Inform SAL that the flow on the specified node has been removed Consumer
+     * has to expect this notification only for flows which were installed with
+     * an idle or hard timeout specified.
+     * 
+     * @param node
+     *            the network node on which the flow got removed
+     * @param flow
+     *            the flow that got removed. Note: It may contain only the Match
+     *            and flow parameters fields. Actions may not be present.
+     */
+    public void flowRemoved(Node node, Flow flow);
+}
index 12e772890e697bf373b39cd2fe8a5d5e0c60546a..175a11718bff431f80e113da0da837ccadd47cc2 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -16,48 +15,51 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * Represents the generic matching field
- *
+ * 
  */
 
 @XmlRootElement
 @XmlAccessorType(XmlAccessType.NONE)
-
 public class MatchField implements Cloneable, Serializable {
-       private static final long serialVersionUID = 1L;
-       private static final Logger logger = LoggerFactory
+    private static final long serialVersionUID = 1L;
+    private static final Logger logger = LoggerFactory
             .getLogger(MatchField.class);
-       private MatchType type; // the field we want to match
+    private MatchType type; // the field we want to match
     private Object value; // the value of the field we want to match
-    private Object mask; // the value of the mask we want to match on the specified field
+    private Object mask; // the value of the mask we want to match on the
+                         // specified field
     private transient boolean isValid;
 
     // To satisfy JAXB
+    @SuppressWarnings("unused")
     private MatchField() {
     }
+
     /**
      * Mask based match constructor
-     *
+     * 
      * @param type
      * @param value
-     * @param mask   has to be of the same class type of value. A null mask means full match
+     * @param mask
+     *            has to be of the same class type of value. A null mask means
+     *            full match
      */
     public MatchField(MatchType type, Object value, Object mask) {
         this.type = type;
         this.value = value;
         this.mask = mask;
-        this.isValid = checkValueType() && checkValues(); // Keep this logic, value checked only if type check is fine
+        // Keep this logic, value checked only if type check is fine
+        this.isValid = checkValueType() && checkValues();
     }
 
     /**
      * Full match constructor
-     *
+     * 
      * @param type
      * @param value
      */
@@ -65,54 +67,56 @@ public class MatchField implements Cloneable, Serializable {
         this.type = type;
         this.value = value;
         this.mask = null;
-        this.isValid = checkValueType() && checkValues(); // Keep this logic, value checked only if type check is fine
+        // Keep this logic, value checked only if type check is fine
+        this.isValid = checkValueType() && checkValues();
     }
 
     /**
      * Returns the value set for this match field
-     *
+     * 
      * @return
      */
     public Object getValue() {
         return value;
     }
-    
-    @XmlElement(name="value")
+
+    @XmlElement(name = "value")
     private String getValueString() {
-       return type.stringify(value);
+        return type.stringify(value);
     }
 
     /**
      * Returns the type field this match field object is for
-     *
+     * 
      * @return
      */
     public MatchType getType() {
         return type;
     }
 
-    @XmlElement(name="type")
+    @XmlElement(name = "type")
     private String getTypeString() {
-       return type.toString();
+        return type.toString();
     }
 
     /**
-     * Returns the mask value set for this field match
-     * A null mask means this is a full match
+     * Returns the mask value set for this field match A null mask means this is
+     * a full match
+     * 
      * @return
      */
     public Object getMask() {
         return mask;
     }
-    
-    @XmlElement(name="mask")
+
+    @XmlElement(name = "mask")
     private String getMaskString() {
-       return type.stringify(mask); 
+        return type.stringify(mask);
     }
 
     /**
      * Returns the bitmask set for this field match
-     *
+     * 
      * @return
      */
     public long getBitMask() {
@@ -121,7 +125,7 @@ public class MatchField implements Cloneable, Serializable {
 
     /**
      * Returns whether the field match configuration is valid or not
-     *
+     * 
      * @return
      */
     public boolean isValid() {
@@ -190,17 +194,36 @@ public class MatchField implements Cloneable, Serializable {
     }
 
     @Override
-    public int hashCode() {
-        return HashCodeBuilder.reflectionHashCode(this);
+    public String toString() {
+        return type + "(" + getValueString() + "," + getMaskString() + ")";
     }
 
     @Override
-    public boolean equals(Object obj) {
-        return EqualsBuilder.reflectionEquals(this, obj);
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((mask == null) ? 0 : mask.hashCode());
+        result = prime * result + ((type == null) ? 0 : type.hashCode());
+        result = prime * result + ((value == null) ? 0 : value.hashCode());
+        return result;
     }
 
     @Override
-    public String toString() {
-        return type + "(" + getValueString() + "," + getMaskString() + ")";
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        MatchField other = (MatchField) obj;
+        if (type != other.type) {
+            return false;
+        }
+        return (type.equalValues(this.value, other.value) && type.equalMasks(
+                this.mask, other.mask));
     }
 }
index 93e5a5874c64787a5fa63cac604030e2f6b5ce68..5ad4bd5b660dbc58e4041a5422205d61edf4a3d0 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
 package org.opendaylight.controller.sal.match;
 
 import java.net.InetAddress;
+import java.util.Arrays;
 
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.utils.HexEncode;
 import org.opendaylight.controller.sal.utils.NetUtils;
 
 /**
- * Represents the binding between the id, the value and mask type and the range values
- * of the elements type that can be matched on the network frame/packet/message
- *
- *
- *
+ * Represents the binding between the id, the value and mask type and the range
+ * values of the elements type that can be matched on the network
+ * frame/packet/message
+ * 
+ * 
+ * 
  */
 public enum MatchType {
-    IN_PORT("inPort", 1 << 0, NodeConnector.class, 1, 0), 
-    DL_SRC("dlSrc", 1 << 1, Byte[].class, 0, 0xffffffffffffL), 
-    DL_DST("dlDst", 1 << 2, Byte[].class, 0, 0xffffffffffffL), 
+    IN_PORT("inPort", 1 << 0, NodeConnector.class, 1, 0),
+    DL_SRC("dlSrc", 1 << 1, Byte[].class, 0, 0xffffffffffffL),
+    DL_DST("dlDst", 1 << 2, Byte[].class, 0, 0xffffffffffffL),
     DL_VLAN("dlVlan", 1 << 3, Short.class, 1, 0xfff), // 2 bytes
     DL_VLAN_PR("dlVlanPriority", 1 << 4, Byte.class, 0, 0x7), // 3 bits
-    DL_OUTER_VLAN("dlOuterVlan", 1 << 5, Short.class, 1, 0xfff), 
-    DL_OUTER_VLAN_PR("dlOuterVlanPriority", 1 << 6, Short.class, 0, 0x7), 
+    DL_OUTER_VLAN("dlOuterVlan", 1 << 5, Short.class, 1, 0xfff),
+    DL_OUTER_VLAN_PR("dlOuterVlanPriority", 1 << 6, Short.class, 0, 0x7),
     DL_TYPE("dlType", 1 << 7, Short.class, 0, 0xffff), // 2 bytes
     NW_TOS("nwTOS", 1 << 8, Byte.class, 0, 0x3f), // 6 bits (DSCP field)
     NW_PROTO("nwProto", 1 << 9, Byte.class, 0, 0xff), // 1 byte
-    NW_SRC("nwSrc", 1 << 10, InetAddress.class, 0, 0), 
-    NW_DST("nwDst", 1 << 11, InetAddress.class, 0, 0), 
+    NW_SRC("nwSrc", 1 << 10, InetAddress.class, 0, 0),
+    NW_DST("nwDst", 1 << 11, InetAddress.class, 0, 0),
     TP_SRC("tpSrc", 1 << 12, Short.class, 1, 0xffff), // 2 bytes
     TP_DST("tpDst", 1 << 13, Short.class, 1, 0xffff); // 2 bytes
 
@@ -71,7 +72,8 @@ public enum MatchType {
     }
 
     /**
-     *  Perform the assignment type validation
+     * Perform the assignment type validation
+     * 
      * @param value
      * @param mask
      * @return
@@ -85,7 +87,8 @@ public enum MatchType {
         Class<?> e = this.dataType();
         Class<?> g = value.getClass();
 
-        // This is all what we need, if value type is same of match required type
+        // This is all what we need, if value type is same of match required
+        // type
         if (g.equals(e)) {
             return true;
         }
@@ -116,6 +119,7 @@ public enum MatchType {
 
     /**
      * Perform the value and mask range validation
+     * 
      * @param value
      * @param mask
      * @return
@@ -158,12 +162,13 @@ public enum MatchType {
 
     /**
      * Return the mask value in 64 bits bitmask form
+     * 
      * @param mask
      * @return
      */
     public long getBitMask(Object mask) {
         if (this.dataType == InetAddress.class) {
-            //TODO handle Inet v4 and v6 v6 will have a second upper mask
+            // TODO handle Inet v4 and v6 v6 will have a second upper mask
             return 0;
         }
         if (this.dataType() == Byte[].class) {
@@ -173,7 +178,6 @@ public enum MatchType {
             byte mac[] = (byte[]) mask;
             long bitmask = 0;
             for (short i = 0; i < 6; i++) {
-                //                             bitmask |= (((long)mac[i] & 0xffL) << (long)((5-i)*8));
                 bitmask |= (((long) mac[i] & 0xffL) << ((5 - i) * 8));
             }
             return bitmask;
@@ -193,32 +197,76 @@ public enum MatchType {
         return 0L;
     }
 
-       public String stringify(Object value) {
-               if (value == null) {
-                       return null;
-               }
-               
-               switch (this) {
-               case DL_DST:
-               case DL_SRC:
-                       return HexEncode.bytesToHexStringFormat((byte[])value);
-               case DL_TYPE:
-               case DL_VLAN:
-                       return ((Integer) NetUtils.getUnsignedShort((Short)value))
-                                       .toString();
-               case NW_SRC:
-               case NW_DST:
-                       return ((InetAddress)value).getHostAddress();
-               case NW_TOS:
-                       return ((Integer) NetUtils.getUnsignedByte((Byte)value))
-                                       .toString();
-               case TP_SRC:
-               case TP_DST:
-                       return ((Integer) NetUtils.getUnsignedShort((Short)value))
-                                       .toString();
-               default:
-                       break;
-               }
-               return value.toString();
-       }
+    public String stringify(Object value) {
+        if (value == null) {
+            return null;
+        }
+
+        switch (this) {
+        case DL_DST:
+        case DL_SRC:
+            return HexEncode.bytesToHexStringFormat((byte[]) value);
+        case DL_TYPE:
+        case DL_VLAN:
+            return ((Integer) NetUtils.getUnsignedShort((Short) value))
+                    .toString();
+        case NW_SRC:
+        case NW_DST:
+            return ((InetAddress) value).getHostAddress();
+        case NW_TOS:
+            return ((Integer) NetUtils.getUnsignedByte((Byte) value))
+                    .toString();
+        case TP_SRC:
+        case TP_DST:
+            return ((Integer) NetUtils.getUnsignedShort((Short) value))
+                    .toString();
+        default:
+            break;
+        }
+        return value.toString();
+    }
+
+    public boolean equalValues(Object a, Object b) {
+        if (a == b) {
+            return true;
+        }
+        if (a == null || b == null) {
+            return false;
+        }
+        switch (this) {
+        case DL_DST:
+        case DL_SRC:
+            return Arrays.equals((byte[]) a, (byte[]) b);
+        default:
+            return a.equals(b);
+        }
+    }
+
+    public boolean equalMasks(Object a, Object b) {
+        if (a == b) {
+            return true;
+        }
+        switch (this) {
+        case NW_SRC:
+        case NW_DST:
+            /*
+             * For network address mask, network node may return full mask for
+             * flows the controller generated with a null mask object
+             */
+            byte maskBytes[] = null;
+            if (a == null) {
+                maskBytes = ((InetAddress) b).getAddress();
+            } else if (b == null) {
+                maskBytes = ((InetAddress) a).getAddress();
+            }
+            if (maskBytes != null) {
+                return (NetUtils.getSubnetMaskLength(maskBytes) == 0);
+            }
+        default:
+            if (a == null) {
+                return false;
+            }
+            return a.equals(b);
+        }
+    }
 }
index 7ea9360300659c7babeb93ba87f22eb4253a22ff..b183240d4316bcf48f7d4b34a895a91518aff7c9 100644 (file)
@@ -42,6 +42,7 @@ public interface IPluginOutTopologyService {
     /**
      * Called when an Edge utilization is above the safety threshold
      * configured on the controller
+     * 
      * @param edge
      */
     public void edgeOverUtilized(Edge edge);
index 9893a06e02f2d2179d1dedfa4405d30aefb0f5fe..503e08e714568bc00118d5ad7626fd1ce396b2b7 100644 (file)
@@ -10,74 +10,98 @@ package org.opendaylight.controller.sal.utils;
 
 /**
  * Represents the return object of the osgi service interfaces function calls.
- * It contains a code {@code StatusCode} representing the result of the call
- * and a string which describes a failure reason (if any) in human readable form.
+ * It contains a code {@code StatusCode} representing the result of the call and
+ * a string which describes a failure reason (if any) in human readable form.
  */
 public class Status {
-       StatusCode code;
-       String description;
-       
-       /**
-        * Generates an instance of the Status class.
-        * 
-        * @param errorCode The status code. If passed as null, code will be 
-        * stored as {@code StatusCode.UNDEFINED}
-        * @param description The human readable description of the status. If passed
-        * as null, description will be inferred by the code
-        */
-       public Status(StatusCode errorCode, String description) {
-               this.code = (errorCode != null)? errorCode : StatusCode.UNDEFINED;
-               this.description = (description != null)? description : this.code.toString();
-       }
-       
-       /**
-        * Returns the status code
-        * @return the {@code StatusCode} representing the status code 
-        */
-       public StatusCode getCode() {
-               return code;
-       }
-       
-       /**
-        * Returns a human readable description of the failure if any
-        * @return a string representing the reason of failure
-        */
-       public String getDescription() {
-               return description;
-       }
-       
-       /**
-        * Tells whether the status is successful
-        * @return true if the Status code is {@code StatusCode.SUCCESS}
-        */
-       public boolean isSuccess() {
-               return code == StatusCode.SUCCESS;
-       }
-       
-       @Override
-       public String toString() {
-               return code + ": " + description;
-       }
+    StatusCode code;
+    String description;
 
-       @Override
-       public int hashCode() {
-               final int prime = 31;
-               int result = 1;
-               result = prime * result + ((code == null) ? 0 : code.hashCode());
-               return result;
-       }
+    /**
+     * Generates an instance of the Status class. This is used as return code
+     * for internal API2 function calls. This constructor allows to specify,
+     * beside the Status Code, a custom human readable description to add more
+     * information about the status.
+     * 
+     * @param errorCode
+     *            The status code. If passed as null, code will be stored as
+     *            {@code StatusCode.UNDEFINED}
+     * @param description
+     *            The human readable description of the status. If passed as
+     *            null, description will be inferred by the code
+     */
+    public Status(StatusCode errorCode, String description) {
+        this.code = (errorCode != null) ? errorCode : StatusCode.UNDEFINED;
+        this.description = (description != null) ? description : this.code
+                .toString();
+    }
 
-       @Override
-       public boolean equals(Object obj) {
-               if (this == obj)
-                       return true;
-               if (obj == null)
-                       return false;
-               if (getClass() != obj.getClass())
-                       return false;
-               Status other = (Status) obj;
-               if (code != other.code)
-                       return false;
-               return true;
-       }
+    /**
+     * Generates an instance of the Status class based on the passed StatusCode
+     * only. The description field of the Status object will be inferred by the
+     * status code.
+     * 
+     * @param errorCode
+     *            The status code. If passed as null, code will be stored as
+     *            {@code StatusCode.UNDEFINED}
+     */
+    public Status(StatusCode errorCode) {
+        this.code = (errorCode != null) ? errorCode : StatusCode.UNDEFINED;
+        this.description = (description != null) ? description : this.code
+                .toString();
+    }
+
+    /**
+     * Returns the status code
+     * 
+     * @return the {@code StatusCode} representing the status code
+     */
+    public StatusCode getCode() {
+        return code;
+    }
+
+    /**
+     * Returns a human readable description of the failure if any
+     * 
+     * @return a string representing the reason of failure
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Tells whether the status is successful
+     * 
+     * @return true if the Status code is {@code StatusCode.SUCCESS}
+     */
+    public boolean isSuccess() {
+        return code == StatusCode.SUCCESS;
+    }
+
+    @Override
+    public String toString() {
+        return code + ": " + description;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((code == null) ? 0 : code.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Status other = (Status) obj;
+        if (code != other.code)
+            return false;
+        return true;
+    }
 }
index 722f9935180988d421aaccd44ba80793fdef3bae..f257befd3c3d64ed15f8dcc76cd87b501135f49d 100644 (file)
@@ -304,6 +304,49 @@ public class MatchTest {
         }
     }
 
+    @Test
+    public void testEqualityNetMask() throws Exception {
+
+        InetAddress srcIP = InetAddress.getByName("1.1.1.1");
+        InetAddress ipMask = InetAddress.getByName("255.255.255.255");
+        InetAddress srcIP2 = InetAddress.getByName("1.1.1.1");
+        InetAddress ipMask2 = null;
+        short ethertype = EtherTypes.IPv4.shortValue();
+        short ethertype2 = EtherTypes.IPv4.shortValue();
+       
+        /*
+         * Create a SAL Flow aFlow
+         */
+        Match match1 = new Match();
+        Match match2 = new Match();
+        
+        match1.setField(MatchType.DL_TYPE, ethertype);
+        match1.setField(MatchType.NW_SRC, srcIP, ipMask);
+
+        match2.setField(MatchType.DL_TYPE, ethertype2);
+        match2.setField(MatchType.NW_SRC, srcIP2, ipMask2);
+
+        Assert.assertTrue(match1.equals(match2));
+        
+        ipMask2 = InetAddress.getByName("255.255.255.255");
+        match2.setField(MatchType.NW_SRC, srcIP2, ipMask2);
+
+        srcIP = InetAddress.getByName("2001:420:281:1004:407a:57f4:4d15:c355");
+        srcIP2 = InetAddress.getByName("2001:420:281:1004:407a:57f4:4d15:c355");
+        ipMask = null;
+        ipMask2 = InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
+        ethertype = EtherTypes.IPv6.shortValue();
+        ethertype2 = EtherTypes.IPv6.shortValue();
+        match1.setField(MatchType.DL_TYPE, ethertype);
+        match1.setField(MatchType.NW_SRC, srcIP, ipMask);
+
+        match2.setField(MatchType.DL_TYPE, ethertype2);
+        match2.setField(MatchType.NW_SRC, srcIP2, ipMask2);
+
+        Assert.assertTrue(match1.equals(match2));
+    }
+    
     @Test
     public void testCloning() throws Exception {
         Node node = NodeCreator.createOFNode(7l);
index 1d7732af4424f48368bd8870c1d59b82d494b043..99690802e3cdd5e9539c8e0a5c33a18ccec7b3d6 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -10,8 +9,10 @@
 package org.opendaylight.controller.sal.implementation.internal;
 
 import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener;
 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
 import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
+import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService;
 import org.opendaylight.controller.sal.inventory.IInventoryService;
 import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
 import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
@@ -35,32 +36,31 @@ public class Activator extends ComponentActivatorAbstractBase {
             .getLogger(Activator.class);
 
     /**
-     * Function called when the activator starts just after some
-     * initializations are done by the
-     * ComponentActivatorAbstractBase.
-     *
+     * Function called when the activator starts just after some initializations
+     * are done by the ComponentActivatorAbstractBase.
+     * 
      */
     public void init() {
 
     }
 
     /**
-     * Function called when the activator stops just before the
-     * cleanup done by ComponentActivatorAbstractBase
-     *
+     * Function called when the activator stops just before the cleanup done by
+     * ComponentActivatorAbstractBase
+     * 
      */
     public void destroy() {
 
     }
 
     /**
-     * Function that is used to communicate to dependency manager the
-     * list of known implementations for services inside a container
-     *
-     *
+     * Function that is used to communicate to dependency manager the list of
+     * known implementations for services inside a container
+     * 
+     * 
      * @return An array containing all the CLASS objects that will be
-     * instantiated in order to get an fully working implementation
-     * Object
+     *         instantiated in order to get an fully working implementation
+     *         Object
      */
     public Object[] getImplementations() {
         Object[] res = { Topology.class, Inventory.class,
@@ -70,97 +70,107 @@ public class Activator extends ComponentActivatorAbstractBase {
     }
 
     /**
-     * Function that is called when configuration of the dependencies
-     * is required.
-     *
-     * @param c dependency manager Component object, used for
-     * configuring the dependencies exported and imported
-     * @param imp Implementation class that is being configured,
-     * needed as long as the same routine can configure multiple
-     * implementations
-     * @param containerName The containerName being configured, this allow
-     * also optional per-container different behavior if needed, usually
-     * should not be the case though.
+     * Function that is called when configuration of the dependencies is
+     * required.
+     * 
+     * @param c
+     *            dependency manager Component object, used for configuring the
+     *            dependencies exported and imported
+     * @param imp
+     *            Implementation class that is being configured, needed as long
+     *            as the same routine can configure multiple implementations
+     * @param containerName
+     *            The containerName being configured, this allow also optional
+     *            per-container different behavior if needed, usually should not
+     *            be the case though.
      */
     public void configureInstance(Component c, Object imp, String containerName) {
         if (imp.equals(Topology.class)) {
             // export the service for Apps and Plugins
-            c.setInterface(new String[] {
-                    IPluginOutTopologyService.class.getName(),
-                    ITopologyService.class.getName() }, null);
+            c.setInterface(
+                    new String[] { IPluginOutTopologyService.class.getName(),
+                            ITopologyService.class.getName() }, null);
 
             // There can be multiple Topology listeners or there could
             // be none, hence the dependency is optional
-            c.add(createContainerServiceDependency(containerName).setService(
-                    IListenTopoUpdates.class).setCallbacks("setUpdateService",
-                    "unsetUpdateService").setRequired(false));
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IListenTopoUpdates.class)
+                    .setCallbacks("setUpdateService", "unsetUpdateService")
+                    .setRequired(false));
 
             // There can be multiple southbound plugins or there could
             // be none, the dependency is optional
-            c.add(createContainerServiceDependency(containerName).setService(
-                    IPluginInTopologyService.class).setCallbacks(
-                    "setPluginService", "unsetPluginService")
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IPluginInTopologyService.class)
+                    .setCallbacks("setPluginService", "unsetPluginService")
                     .setRequired(false));
         }
 
         if (imp.equals(Inventory.class)) {
             // export the service
-            c.setInterface(new String[] {
-                    IPluginOutInventoryService.class.getName(),
-                    IInventoryService.class.getName() }, null);
+            c.setInterface(
+                    new String[] { IPluginOutInventoryService.class.getName(),
+                            IInventoryService.class.getName() }, null);
 
             // Now lets add a service dependency to make sure the
             // provider of service exists
-            c.add(createContainerServiceDependency(containerName).setService(
-                    IListenInventoryUpdates.class).setCallbacks(
-                    "setUpdateService", "unsetUpdateService")
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IListenInventoryUpdates.class)
+                    .setCallbacks("setUpdateService", "unsetUpdateService")
                     .setRequired(false));
-            c
-                    .add(createContainerServiceDependency(containerName)
-                            .setService(IPluginInInventoryService.class)
-                            .setCallbacks("setPluginService",
-                                    "unsetPluginService").setRequired(true));
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IPluginInInventoryService.class)
+                    .setCallbacks("setPluginService", "unsetPluginService")
+                    .setRequired(true));
         }
 
         if (imp.equals(FlowProgrammerService.class)) {
-            // It is the provider of IFlowProgrammerService
-            c.setInterface(IFlowProgrammerService.class.getName(), null);
-            //It is also the consumer of IPluginInFlowProgrammerService
-            c.add(createServiceDependency().setService(
-                    IPluginInFlowProgrammerService.class).setCallbacks(
-                    "setService", "unsetService").setRequired(true));
+            c.setInterface(
+                    new String[] { IFlowProgrammerService.class.getName(),
+                            IPluginOutFlowProgrammerService.class.getName() },
+                    null);
+
+            c.add(createServiceDependency()
+                    .setService(IPluginInFlowProgrammerService.class)
+                    .setCallbacks("setService", "unsetService")
+                    .setRequired(false));
+            c.add(createServiceDependency()
+                    .setService(IFlowProgrammerListener.class)
+                    .setCallbacks("setListener", "unsetListener")
+                    .setRequired(false));
         }
 
         if (imp.equals(ReadService.class)) {
             // It is the provider of IReadService
             c.setInterface(IReadService.class.getName(), null);
 
-            //It is also the consumer of IPluginInReadService
-            c.add(createContainerServiceDependency(containerName).setService(
-                    IPluginInReadService.class).setCallbacks("setService",
-                    "unsetService").setRequired(true));
+            // It is also the consumer of IPluginInReadService
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IPluginInReadService.class)
+                    .setCallbacks("setService", "unsetService")
+                    .setRequired(true));
         }
 
         /************************/
         /* DATA PACKET SERVICES */
         /************************/
         if (imp.equals(DataPacketService.class)) {
-            c.setInterface(new String[] {
-                    IPluginOutDataPacketService.class.getName(),
-                    IDataPacketService.class.getName() }, null);
+            c.setInterface(
+                    new String[] { IPluginOutDataPacketService.class.getName(),
+                            IDataPacketService.class.getName() }, null);
 
             // Optionally use PluginInDataService if any southbound
             // protocol plugin exists
-            c.add(createContainerServiceDependency(containerName).setService(
-                    IPluginInDataPacketService.class).setCallbacks(
-                    "setPluginInDataService", "unsetPluginInDataService")
-                    .setRequired(false));
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IPluginInDataPacketService.class)
+                    .setCallbacks("setPluginInDataService",
+                            "unsetPluginInDataService").setRequired(false));
 
             // Optionally listed to IListenDataPacket services
-            c.add(createContainerServiceDependency(containerName).setService(
-                    IListenDataPacket.class).setCallbacks(
-                    "setListenDataPacket", "unsetListenDataPacket")
-                    .setRequired(false));
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IListenDataPacket.class)
+                    .setCallbacks("setListenDataPacket",
+                            "unsetListenDataPacket").setRequired(false));
         }
     }
 }
index d2a49b9208fac68118ca27e70086ef9b0f59738a..0cc2a1943d3bd027b8426298ff588b30a21e6d89 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -14,7 +13,9 @@ import java.util.concurrent.ConcurrentHashMap;
 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 org.eclipse.osgi.framework.console.CommandInterpreter;
 import org.eclipse.osgi.framework.console.CommandProvider;
@@ -29,8 +30,10 @@ import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.Node.NodeIDType;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener;
 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
 import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
+import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService;
 import org.opendaylight.controller.sal.match.Match;
 import org.opendaylight.controller.sal.match.MatchType;
 import org.opendaylight.controller.sal.utils.StatusCode;
@@ -44,35 +47,37 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * The SAL Flow Programmer Service. It dispatches the flow programming
- * requests to the proper SDN protocol plugin
- *
- *
- *
+ * The SAL Flow Programmer Service. It dispatches the flow programming requests
+ * to the proper SDN protocol plugin and it notifies about asynchronous messages
+ * received from the network node related to flow programming.
  */
 public class FlowProgrammerService implements IFlowProgrammerService,
-        CommandProvider {
+        IPluginOutFlowProgrammerService, CommandProvider {
 
     protected static final Logger logger = LoggerFactory
             .getLogger(FlowProgrammerService.class);
-    private ConcurrentHashMap<String, IPluginInFlowProgrammerService>
-        pluginFlowProgrammer =
-        new ConcurrentHashMap<String, IPluginInFlowProgrammerService>();
+    private ConcurrentHashMap<String, IPluginInFlowProgrammerService> pluginFlowProgrammer;
+    private Set<IFlowProgrammerListener> listener;
+
+    public FlowProgrammerService() {
+        pluginFlowProgrammer = new ConcurrentHashMap<String, IPluginInFlowProgrammerService>();
+        listener = new HashSet<IFlowProgrammerListener>();
+    }
 
     /**
      * Function called by the dependency manager when all the required
      * dependencies are satisfied
-     *
+     * 
      */
     void init() {
         logger.debug("INIT called!");
     }
 
     /**
-     * Function called by the dependency manager when at least one
-     * dependency become unsatisfied or when the component is shutting
-     * down because for example bundle is being stopped.
-     *
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     * 
      */
     void destroy() {
         // Clear previous registration to avoid they are left hanging
@@ -81,10 +86,9 @@ public class FlowProgrammerService implements IFlowProgrammerService,
     }
 
     /**
-     * Function called by dependency manager after "init ()" is called
-     * and after the services provided by the class are registered in
-     * the service registry
-     *
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     * 
      */
     void start() {
         logger.debug("START called!");
@@ -93,10 +97,10 @@ public class FlowProgrammerService implements IFlowProgrammerService,
     }
 
     /**
-     * Function called by the dependency manager before the services
-     * exported by the component are unregistered, this will be
-     * followed by a "destroy ()" calls
-     *
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     * 
      */
     void stop() {
         logger.debug("STOP called!");
@@ -113,8 +117,8 @@ public class FlowProgrammerService implements IFlowProgrammerService,
         String type = null;
         for (Object e : props.entrySet()) {
             Map.Entry entry = (Map.Entry) e;
-            logger.trace("Prop key:({}) value:({})",entry.getKey(),
-                         entry.getValue());
+            logger.trace("Prop key:({}) value:({})", entry.getKey(),
+                    entry.getValue());
         }
 
         Object value = props.get("protocolPluginType");
@@ -126,12 +130,11 @@ public class FlowProgrammerService implements IFlowProgrammerService,
                     + "protocolPluginType provided");
         } else {
             this.pluginFlowProgrammer.put(type, s);
-            logger.debug("Stored the pluginFlowProgrammer for type: {}",type);
+            logger.debug("Stored the pluginFlowProgrammer for type: {}", type);
         }
     }
 
-    public void unsetService(Map props,
-                             IPluginInFlowProgrammerService s) {
+    public void unsetService(Map props, IPluginInFlowProgrammerService s) {
         if (this.pluginFlowProgrammer == null) {
             logger.error("pluginFlowProgrammer store null");
             return;
@@ -141,8 +144,8 @@ public class FlowProgrammerService implements IFlowProgrammerService,
         logger.debug("Received unsetpluginFlowProgrammer request");
         for (Object e : props.entrySet()) {
             Map.Entry entry = (Map.Entry) e;
-            logger.trace("Prop key:({}) value:({})",entry.getKey(),
-                       entry.getValue());
+            logger.trace("Prop key:({}) value:({})", entry.getKey(),
+                    entry.getValue());
         }
 
         Object value = props.get("protocoloPluginType");
@@ -158,12 +161,20 @@ public class FlowProgrammerService implements IFlowProgrammerService,
         }
     }
 
+    public void setListener(IFlowProgrammerListener s) {
+        this.listener.add(s);
+    }
+
+    public void unsetListener(IFlowProgrammerListener s) {
+        this.listener.remove(s);
+    }
+
     @Override
     public Status addFlow(Node node, Flow flow) {
         if (pluginFlowProgrammer != null) {
             if (this.pluginFlowProgrammer.get(node.getType()) != null) {
-                return this.pluginFlowProgrammer.get(node.getType())
-                    .addFlow(node, flow);
+                return this.pluginFlowProgrammer.get(node.getType()).addFlow(
+                        node, flow);
             }
         }
         return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
@@ -174,7 +185,7 @@ public class FlowProgrammerService implements IFlowProgrammerService,
         if (pluginFlowProgrammer != null) {
             if (this.pluginFlowProgrammer.get(node.getType()) != null) {
                 return this.pluginFlowProgrammer.get(node.getType())
-                    .removeFlow(node, flow);
+                        .removeFlow(node, flow);
             }
         }
         return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
@@ -185,7 +196,7 @@ public class FlowProgrammerService implements IFlowProgrammerService,
         if (pluginFlowProgrammer != null) {
             if (this.pluginFlowProgrammer.get(node.getType()) != null) {
                 return this.pluginFlowProgrammer.get(node.getType())
-                    .removeAllFlows(node);
+                        .removeAllFlows(node);
             }
         }
         return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
@@ -196,12 +207,19 @@ public class FlowProgrammerService implements IFlowProgrammerService,
         if (pluginFlowProgrammer != null) {
             if (this.pluginFlowProgrammer.get(node.getType()) != null) {
                 return this.pluginFlowProgrammer.get(node.getType())
-                    .modifyFlow(node, oldFlow, newFlow);
+                        .modifyFlow(node, oldFlow, newFlow);
             }
         }
         return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
     }
 
+    @Override
+    public void flowRemoved(Node node, Flow flow) {
+        for (IFlowProgrammerListener l : listener) {
+            l.flowRemoved(node, flow);
+        }
+    }
+
     // ---------------- OSGI TEST CODE ------------------------------//
 
     private void registerWithOSGIConsole() {
@@ -215,10 +233,8 @@ public class FlowProgrammerService implements IFlowProgrammerService,
     public String getHelp() {
         StringBuffer help = new StringBuffer();
         help.append("---SAL Flow Programmer testing commands---\n");
-        help
-                .append("\t addflow <sid> - Add a sample flow to the openflow switch <sid>\n");
-        help
-                .append("\t removeflow <sid> - Remove the sample flow from the openflow switch <sid>\n");
+        help.append("\t addflow <sid> - Add a sample flow to the openflow switch <sid>\n");
+        help.append("\t removeflow <sid> - Remove the sample flow from the openflow switch <sid>\n");
         return help.toString();
     }
 
@@ -256,8 +272,8 @@ public class FlowProgrammerService implements IFlowProgrammerService,
         Flow flowA = getSampleFlow(node);
         Flow flowB = getSampleFlow(node);
         Match matchB = flowB.getMatch();
-        matchB.setField(MatchType.NW_DST, InetAddress
-                .getByName("190.190.190.190"));
+        matchB.setField(MatchType.NW_DST,
+                InetAddress.getByName("190.190.190.190"));
         flowB.setMatch(matchB);
         ci.println(this.modifyFlow(node, flowA, flowB));
     }
@@ -380,15 +396,17 @@ public class FlowProgrammerService implements IFlowProgrammerService,
                 .getByName("2001:420:281:1004:407a:57f4:4d15:c355");
         InetAddress dstIP = InetAddress
                 .getByName("2001:420:281:1004:e123:e688:d655:a1b0");
-        InetAddress ipMask = null; //InetAddress.getByName("ffff:ffff:ffff:ffff:0:0:0:0"); V6Match implementation assumes no mask is specified
-        InetAddress ipMask2 = null; //InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0");
+        InetAddress ipMask = null; // InetAddress.getByName("ffff:ffff:ffff:ffff:0:0:0:0");
+                                   // V6Match implementation assumes no mask is
+                                   // specified
+        InetAddress ipMask2 = null; // InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0");
         short ethertype = EtherTypes.IPv6.shortValue();
         short vlan = (short) 27;
         byte vlanPr = (byte) 3;
         Byte tos = 4;
         byte proto = IPProtocols.UDP.byteValue();
         short src = (short) 5500;
-        //short dst = 80;
+        // short dst = 80;
 
         /*
          * Create a SAL Flow aFlow
@@ -399,13 +417,16 @@ public class FlowProgrammerService implements IFlowProgrammerService,
         match.setField(MatchType.DL_DST, dstMac);
         match.setField(MatchType.DL_TYPE, ethertype);
         match.setField(MatchType.DL_VLAN, vlan);
-        match.setField(MatchType.DL_VLAN_PR, vlanPr); //V6Match does not handle this properly...
+        match.setField(MatchType.DL_VLAN_PR, vlanPr); // V6Match does not handle
+                                                      // this properly...
         match.setField(MatchType.NW_SRC, srcIP, ipMask);
         match.setField(MatchType.NW_DST, dstIP, ipMask2);
         match.setField(MatchType.NW_TOS, tos);
         match.setField(MatchType.NW_PROTO, proto);
-        match.setField(MatchType.TP_SRC, src); //V6Match does not handle this properly...
-        //match.setField(MatchType.TP_DST, dst); V6Match does not handle this properly...
+        match.setField(MatchType.TP_SRC, src); // V6Match does not handle this
+                                               // properly...
+        // match.setField(MatchType.TP_DST, dst); V6Match does not handle this
+        // properly...
 
         List<Action> actions = new ArrayList<Action>();
         actions.add(new Output(oport));
@@ -418,4 +439,5 @@ public class FlowProgrammerService implements IFlowProgrammerService,
 
         return flow;
     }
+
 }