From 5ac5f9d4d8f549f152c802de461c766588b992c4 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Wed, 17 Apr 2013 18:48:44 -0700 Subject: [PATCH] Controller to listen to expired flow removal message - Added plugin-to-FM async notification path for Flow Programmer so that functional modules can receive notification of flow removal sent by switch - On flow programming phase, instruct switch to notify controller about flow removal only if hard or idle timeout is set - Have FRM listen to flow removal message so that it updates the sw view of installed flows and the static flow config installation status accordingly - Changed equals logic in MatchField as a null mask object for net address is equivalent to a /32 (or /128) bitmask - Removed strict dependencies in SAL Activator. SAL services startup should not depend on external services - Enforced the sun_doding_style.xml in newly added or modified files Change-Id: Ifc913ceef87aac0b4694bcd7c47f29d5cb10c6ed Signed-off-by: Alessandro Boch --- .../internal/Activator.java | 7 +- .../internal/ForwardingRulesManagerImpl.java | 612 +++++++++--------- .../northbound/HostTrackerNorthbound.java | 1 + .../openflow/IFlowProgrammerNotifier.java | 22 + .../openflow/internal/Activator.java | 322 +++++---- .../openflow/internal/FlowConverter.java | 124 ++-- .../internal/FlowProgrammerNotifier.java | 86 +++ .../internal/FlowProgrammerService.java | 282 +++++--- .../internal/OFStatisticsManager.java | 2 +- .../v6extension/V6FlowMod.java | 21 +- .../authorization/IResourceAuthorization.java | 20 +- .../IFlowProgrammerListener.java | 19 + .../IFlowProgrammerService.java | 13 +- .../IPluginInFlowProgrammerService.java | 24 +- .../IPluginOutFlowProgrammerService.java | 31 + .../controller/sal/match/MatchField.java | 91 ++- .../controller/sal/match/MatchType.java | 138 ++-- .../topology/IPluginOutTopologyService.java | 1 + .../controller/sal/utils/Status.java | 156 +++-- .../controller/sal/match/MatchTest.java | 43 ++ .../implementation/internal/Activator.java | 142 ++-- .../internal/FlowProgrammerService.java | 116 ++-- 22 files changed, 1417 insertions(+), 856 deletions(-) create mode 100644 opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IFlowProgrammerNotifier.java create mode 100644 opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerNotifier.java create mode 100644 opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerListener.java create mode 100644 opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginOutFlowProgrammerService.java diff --git a/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/Activator.java b/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/Activator.java index 9da0970340..8578e8492e 100644 --- a/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/Activator.java +++ b/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/Activator.java @@ -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); diff --git a/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManagerImpl.java b/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManagerImpl.java index 6cdc785a19..58f1e18730 100644 --- a/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManagerImpl.java +++ b/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManagerImpl.java @@ -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, CommandProvider { + ICacheUpdateAware, 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> nodeFlows; private ConcurrentMap> 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 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 toInstallList = deriveInstallEntries(flowEntry - .clone(), container.getContainerFlows()); + List 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 toInstallSafe = new ArrayList(); 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 deriveInstallEntries(FlowEntry request, List 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 toInstallSafe = new ArrayList(); 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 installedList = deriveInstallEntries(flowEntry - .clone(), container.getContainerFlows()); + List installedList = deriveInstallEntries( + flowEntry.clone(), container.getContainerFlows()); Set 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 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 oldCouples = new ArrayList(); @@ -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>) 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>) 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) 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) 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) 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) 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>) 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) 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 toRemove = new ArrayList(); - for (Entry entry : staticFlows.entrySet()) { + for (Entry 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 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 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 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 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 propMap) { + UpdateType type, Map propMap) { } private FlowConfig getDerivedFlowConfig(FlowConfig original, @@ -1887,8 +1886,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, @Override public void portGroupChanged(PortGroupConfig config, Map data, boolean add) { - log.info("PortGroup Changed for :" + config + " Data: " - + portGroupData); + log.info("PortGroup Changed for :" + config + " Data: " + portGroupData); Map existingData = portGroupData.get(config); if (existingData != null) { for (Map.Entry 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()); - 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 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); + } + } diff --git a/opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthbound.java b/opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthbound.java index d79c4dab89..2275ee98da 100644 --- a/opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthbound.java +++ b/opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthbound.java @@ -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 index 0000000000..307176590f --- /dev/null +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IFlowProgrammerNotifier.java @@ -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 { + +} diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java index 45c0211787..26471a7f75 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java @@ -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 props = new Hashtable(); + // 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)); } } } diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java index 7e89cd0a42..47ce283331 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java @@ -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 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 index 0000000000..594164ddcf --- /dev/null +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerNotifier.java @@ -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"); + } + } + +} diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java index 983c7c2190..2926c22c43 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -10,18 +9,38 @@ 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 flowProgrammerNotifiers; + private Map> containerToNc; public FlowProgrammerService() { controller = null; + flowProgrammerNotifiers = new ConcurrentHashMap(); } public void setController(IController core) { @@ -53,37 +73,61 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { } } + public void setFlowProgrammerNotifier(Map 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 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(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 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 target = null; + + switch (type) { + case ADDED: + if (!containerToNc.containsKey(containerName)) { + containerToNc.put(containerName, new HashSet()); + } + 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) { + + } } diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java index bc61f3b071..73dcea574a 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java @@ -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; } } diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6FlowMod.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6FlowMod.java index 47bb2213aa..888d2e63ed 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6FlowMod.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6FlowMod.java @@ -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]; diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/authorization/IResourceAuthorization.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/authorization/IResourceAuthorization.java index cabe571258..8f6cfa4251 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/authorization/IResourceAuthorization.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/authorization/IResourceAuthorization.java @@ -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 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 index 0000000000..c66a3de474 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerListener.java @@ -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 { + +} diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerService.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerService.java index 956942c09c..69972d6776 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerService.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerService.java @@ -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); diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginInFlowProgrammerService.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginInFlowProgrammerService.java index 1fb99e0ab9..79924fc3dd 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginInFlowProgrammerService.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginInFlowProgrammerService.java @@ -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 index 0000000000..2836f77afa --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginOutFlowProgrammerService.java @@ -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); +} diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchField.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchField.java index 12e772890e..175a11718b 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchField.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchField.java @@ -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)); } } diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchType.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchType.java index 93e5a5874c..5ad4bd5b66 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchType.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchType.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -10,31 +9,33 @@ 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); + } + } } diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/topology/IPluginOutTopologyService.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/topology/IPluginOutTopologyService.java index 7ea9360300..b183240d43 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/topology/IPluginOutTopologyService.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/topology/IPluginOutTopologyService.java @@ -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); diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/Status.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/Status.java index 9893a06e02..503e08e714 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/Status.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/Status.java @@ -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; + } } diff --git a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java index 722f993518..f257befd3c 100644 --- a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java +++ b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java @@ -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); diff --git a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/Activator.java b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/Activator.java index 1d7732af44..99690802e3 100644 --- a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/Activator.java +++ b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/Activator.java @@ -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)); } } } diff --git a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/FlowProgrammerService.java b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/FlowProgrammerService.java index d2a49b9208..0cc2a1943d 100644 --- a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/FlowProgrammerService.java +++ b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/FlowProgrammerService.java @@ -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 - pluginFlowProgrammer = - new ConcurrentHashMap(); + private ConcurrentHashMap pluginFlowProgrammer; + private Set listener; + + public FlowProgrammerService() { + pluginFlowProgrammer = new ConcurrentHashMap(); + listener = new HashSet(); + } /** * 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 - Add a sample flow to the openflow switch \n"); - help - .append("\t removeflow - Remove the sample flow from the openflow switch \n"); + help.append("\t addflow - Add a sample flow to the openflow switch \n"); + help.append("\t removeflow - Remove the sample flow from the openflow switch \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 actions = new ArrayList(); actions.add(new Output(oport)); @@ -418,4 +439,5 @@ public class FlowProgrammerService implements IFlowProgrammerService, return flow; } + } -- 2.36.6