X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fforwardingrulesmanager%2Fimplementation%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fforwardingrulesmanager%2Finternal%2FForwardingRulesManager.java;h=b94103fb1c7c9233bb417e93cc74d42bbef498e7;hb=dba0c9b989781d831fc67e6a9e749aa36f48479b;hp=520825762a40e8bfec9b89c5c0541c41edeedfc1;hpb=6fa9558f9afe51ea0221a164d01d6099eb020763;p=controller.git diff --git a/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java b/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java index 520825762a..b94103fb1c 100644 --- a/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java +++ b/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java @@ -11,7 +11,6 @@ package org.opendaylight.controller.forwardingrulesmanager.internal; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; -import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; @@ -29,14 +28,14 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; -import org.eclipse.osgi.framework.console.CommandInterpreter; -import org.eclipse.osgi.framework.console.CommandProvider; import org.opendaylight.controller.clustering.services.CacheConfigException; import org.opendaylight.controller.clustering.services.CacheExistException; import org.opendaylight.controller.clustering.services.ICacheUpdateAware; import org.opendaylight.controller.clustering.services.IClusterContainerServices; import org.opendaylight.controller.clustering.services.IClusterServices; +import org.opendaylight.controller.configuration.ConfigurationObject; import org.opendaylight.controller.configuration.IConfigurationContainerAware; +import org.opendaylight.controller.configuration.IConfigurationContainerService; import org.opendaylight.controller.connectionmanager.IConnectionManager; import org.opendaylight.controller.containermanager.IContainerManager; import org.opendaylight.controller.forwardingrulesmanager.FlowConfig; @@ -69,17 +68,12 @@ import org.opendaylight.controller.sal.match.MatchType; import org.opendaylight.controller.sal.utils.EtherTypes; import org.opendaylight.controller.sal.utils.GlobalConstants; import org.opendaylight.controller.sal.utils.IObjectReader; -import org.opendaylight.controller.sal.utils.NodeCreator; -import org.opendaylight.controller.sal.utils.ObjectReader; -import org.opendaylight.controller.sal.utils.ObjectWriter; import org.opendaylight.controller.sal.utils.Status; import org.opendaylight.controller.sal.utils.StatusCode; import org.opendaylight.controller.switchmanager.IInventoryListener; import org.opendaylight.controller.switchmanager.ISwitchManager; import org.opendaylight.controller.switchmanager.ISwitchManagerAware; import org.opendaylight.controller.switchmanager.Subnet; -import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,22 +91,22 @@ public class ForwardingRulesManager implements IInventoryListener, IObjectReader, ICacheUpdateAware, - CommandProvider, IFlowProgrammerListener { private static final Logger log = LoggerFactory.getLogger(ForwardingRulesManager.class); private static final Logger logsync = LoggerFactory.getLogger("FRMsync"); - private static final String PORTREMOVED = "Port removed"; - private static final String NODEDOWN = "Node is Down"; + private static final String PORT_REMOVED = "Port removed"; + private static final String NODE_DOWN = "Node is Down"; private static final String INVALID_FLOW_ENTRY = "Invalid FlowEntry"; - private String frmFileName; - private String portGroupFileName; + private static final String STATIC_FLOWS_FILE_NAME = "frm_staticflows.conf"; + private static final String PORT_GROUP_FILE_NAME = "portgroup.conf"; private ConcurrentMap staticFlows; private ConcurrentMap staticFlowsOrdinal; private ConcurrentMap portGroupConfigs; private ConcurrentMap> portGroupData; private ConcurrentMap TSPolicies; private IContainerManager containerManager; + private IConfigurationContainerService configurationService; private boolean inContainerMode; // being used by global instance only protected boolean stopping; @@ -160,6 +154,8 @@ public class ForwardingRulesManager implements */ static final String WORK_ORDER_CACHE = "frm.workOrder"; static final String WORK_STATUS_CACHE = "frm.workStatus"; + static final String ORIGINAL_SW_VIEW_CACHE = "frm.originalSwView"; + static final String INSTALLED_SW_VIEW_CACHE = "frm.installedSwView"; /* * Data structure responsible for distributing the FlowEntryInstall requests @@ -335,7 +331,7 @@ public class ForwardingRulesManager implements for (FlowEntryInstall installEntry : toInstallSafe) { // Install and update database - Status ret = addEntriesInternal(installEntry, async); + Status ret = addEntryInternal(installEntry, async); if (ret.isSuccess()) { oneSucceded = true; @@ -472,7 +468,7 @@ public class ForwardingRulesManager implements Status succeeded = null; boolean decouple = false; if (installedList.size() != toInstallList.size()) { - log.info("Modify: New flow entry does not satisfy the same " + log.trace("Modify: New flow entry does not satisfy the same " + "number of container flows as the original entry does"); decouple = true; } @@ -484,7 +480,7 @@ public class ForwardingRulesManager implements */ FlowEntryInstall sameMatchEntry = installedSwView.get(installEntry); if (sameMatchEntry != null && !sameMatchEntry.getOriginal().equals(currentFlowEntry)) { - log.info("Modify: new container flow merged flow entry clashes with existing flow"); + log.trace("Modify: new container flow merged flow entry clashes with existing flow"); decouple = true; } else { toInstallSafe.add(installEntry); @@ -498,7 +494,7 @@ public class ForwardingRulesManager implements } // Install new entries for (FlowEntryInstall newEntry : toInstallSafe) { - succeeded = this.addEntriesInternal(newEntry, async); + succeeded = this.addEntryInternal(newEntry, async); } } else { /* @@ -558,7 +554,9 @@ public class ForwardingRulesManager implements /** * 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 + * the validity checks are passed. + * This function is supposed to be called only on the controller on which + * the IFRM call is executed. * * @param currentEntries * @param newEntries @@ -568,13 +566,13 @@ public class ForwardingRulesManager implements * contain the unique id assigned to this request */ private Status modifyEntryInternal(FlowEntryInstall currentEntries, FlowEntryInstall newEntries, boolean async) { + Status status = new Status(StatusCode.UNDEFINED); FlowEntryDistributionOrderFutureTask futureStatus = distributeWorkOrder(currentEntries, newEntries, UpdateType.CHANGED); if (futureStatus != null) { - Status retStatus = new Status(StatusCode.UNDEFINED); try { - retStatus = futureStatus.get(); - if (retStatus.getCode() + status = futureStatus.get(); + if (status.getCode() .equals(StatusCode.TIMEOUT)) { // A timeout happened, lets cleanup the workMonitor workMonitor.remove(futureStatus.getOrder()); @@ -584,30 +582,31 @@ public class ForwardingRulesManager implements } catch (ExecutionException e) { log.error("", e); } - return retStatus; } else { // Modify the flow on the network node - Status status = async ? programmer.modifyFlowAsync(currentEntries.getNode(), currentEntries.getInstall() - .getFlow(), newEntries.getInstall() - .getFlow()) : programmer.modifyFlow(currentEntries.getNode(), currentEntries.getInstall() - .getFlow(), newEntries.getInstall() - .getFlow()); + status = modifyEntryInHw(currentEntries, newEntries, async); + } - if (!status.isSuccess()) { - log.trace("SDN Plugin failed to program the flow: {}. The failure is: {}", newEntries.getInstall(), - status.getDescription()); - return status; - } + if (!status.isSuccess()) { + log.trace("{} SDN Plugin failed to program the flow: {}. The failure is: {}", + (futureStatus != null) ? "Remote" : "Local", newEntries.getInstall(), status.getDescription()); + return status; + } - log.trace("Modified {} => {}", currentEntries.getInstall(), newEntries.getInstall()); + log.trace("Modified {} => {}", currentEntries.getInstall(), newEntries.getInstall()); - // Update DB - newEntries.setRequestId(status.getRequestId()); - updateLocalDatabase(currentEntries, false); - updateLocalDatabase(newEntries, true); + // Update DB + newEntries.setRequestId(status.getRequestId()); + updateSwViews(currentEntries, false); + updateSwViews(newEntries, true); - return status; - } + return status; + } + + private Status modifyEntryInHw(FlowEntryInstall currentEntries, FlowEntryInstall newEntries, boolean async) { + return async ? programmer.modifyFlowAsync(currentEntries.getNode(), currentEntries.getInstall().getFlow(), + newEntries.getInstall().getFlow()) : programmer.modifyFlow(currentEntries.getNode(), currentEntries + .getInstall().getFlow(), newEntries.getInstall().getFlow()); } /** @@ -676,6 +675,8 @@ public class ForwardingRulesManager implements * 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 + * This function is supposed to be called only on the controller on which + * the IFRM call is executed. * * @param entry * the flow entry to remove @@ -685,13 +686,12 @@ public class ForwardingRulesManager implements * contain the unique id assigned to this request */ private Status removeEntryInternal(FlowEntryInstall entry, boolean async) { + Status status = new Status(StatusCode.UNDEFINED); FlowEntryDistributionOrderFutureTask futureStatus = distributeWorkOrder(entry, null, UpdateType.REMOVED); if (futureStatus != null) { - Status retStatus = new Status(StatusCode.UNDEFINED); try { - retStatus = futureStatus.get(); - if (retStatus.getCode() - .equals(StatusCode.TIMEOUT)) { + status = futureStatus.get(); + if (status.getCode().equals(StatusCode.TIMEOUT)) { // A timeout happened, lets cleanup the workMonitor workMonitor.remove(futureStatus.getOrder()); } @@ -700,28 +700,31 @@ public class ForwardingRulesManager implements } catch (ExecutionException e) { log.error("", e); } - return retStatus; } else { // Mark the entry to be deleted (for CC just in case we fail) entry.toBeDeleted(); // Remove from node - Status status = async ? programmer.removeFlowAsync(entry.getNode(), entry.getInstall() - .getFlow()) : programmer.removeFlow(entry.getNode(), entry.getInstall() - .getFlow()); - - if (!status.isSuccess()) { - log.trace("SDN Plugin failed to remove the flow: {}. The failure is: {}", entry.getInstall(), - status.getDescription()); - return status; - } - log.trace("Removed {}", entry.getInstall()); - - // Update DB - updateLocalDatabase(entry, false); + status = removeEntryInHw(entry, async); + } + if (!status.isSuccess()) { + log.trace("{} SDN Plugin failed to remove the flow: {}. The failure is: {}", + (futureStatus != null) ? "Remote" : "Local", entry.getInstall(), status.getDescription()); return status; } + + log.trace("Removed {}", entry.getInstall()); + + // Update DB + updateSwViews(entry, false); + + return status; + } + + private Status removeEntryInHw(FlowEntryInstall entry, boolean async) { + return async ? programmer.removeFlowAsync(entry.getNode(), entry.getInstall().getFlow()) : programmer + .removeFlow(entry.getNode(), entry.getInstall().getFlow()); } /** @@ -729,6 +732,8 @@ public class ForwardingRulesManager implements * 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. + * This function is supposed to be called only on the controller on which + * the IFRM call is executed. * * @param entry * the flow entry to install @@ -737,14 +742,13 @@ public class ForwardingRulesManager implements * @return the status of this request. In case of asynchronous call, it will * contain the unique id assigned to this request */ - private Status addEntriesInternal(FlowEntryInstall entry, boolean async) { + private Status addEntryInternal(FlowEntryInstall entry, boolean async) { + Status status = new Status(StatusCode.UNDEFINED); FlowEntryDistributionOrderFutureTask futureStatus = distributeWorkOrder(entry, null, UpdateType.ADDED); if (futureStatus != null) { - Status retStatus = new Status(StatusCode.UNDEFINED); try { - retStatus = futureStatus.get(); - if (retStatus.getCode() - .equals(StatusCode.TIMEOUT)) { + status = futureStatus.get(); + if (status.getCode().equals(StatusCode.TIMEOUT)) { // A timeout happened, lets cleanup the workMonitor workMonitor.remove(futureStatus.getOrder()); } @@ -753,27 +757,29 @@ public class ForwardingRulesManager implements } catch (ExecutionException e) { log.error("", e); } - return retStatus; } else { - // Install the flow on the network node - Status status = async ? programmer.addFlowAsync(entry.getNode(), entry.getInstall() - .getFlow()) : programmer.addFlow(entry.getNode(), entry.getInstall() - .getFlow()); + status = addEntryInHw(entry, async); + } - if (!status.isSuccess()) { - log.trace("SDN Plugin failed to program the flow: {}. The failure is: {}", entry.getInstall(), - status.getDescription()); - return status; - } + if (!status.isSuccess()) { + log.trace("{} SDN Plugin failed to program the flow: {}. The failure is: {}", + (futureStatus != null) ? "Remote" : "Local", entry.getInstall(), status.getDescription()); + return status; + } - log.trace("Added {}", entry.getInstall()); + log.trace("Added {}", entry.getInstall()); - // Update DB - entry.setRequestId(status.getRequestId()); - updateLocalDatabase(entry, true); + // Update DB + entry.setRequestId(status.getRequestId()); + updateSwViews(entry, true); - return status; - } + return status; + } + + private Status addEntryInHw(FlowEntryInstall entry, boolean async) { + // Install the flow on the network node + return async ? programmer.addFlowAsync(entry.getNode(), entry.getInstall().getFlow()) : programmer.addFlow( + entry.getNode(), entry.getInstall().getFlow()); } /** @@ -815,10 +821,7 @@ public class ForwardingRulesManager implements return null; } - private void updateLocalDatabase(FlowEntryInstall entry, boolean add) { - // Update the software view - updateSwViewes(entry, add); - + private void updateIndexDatabase(FlowEntryInstall entry, boolean add) { // Update node indexed flow database updateNodeFlowsDB(entry, add); @@ -829,7 +832,7 @@ public class ForwardingRulesManager implements /* * Update the node mapped flows database */ - private void updateSwViewes(FlowEntryInstall flowEntries, boolean add) { + private void updateSwViews(FlowEntryInstall flowEntries, boolean add) { if (add) { originalSwView.put(flowEntries.getOriginal(), flowEntries.getOriginal()); installedSwView.put(flowEntries, flowEntries); @@ -855,6 +858,17 @@ public class ForwardingRulesManager implements } if (add) { + // there may be an already existing entry. + // remove it before adding the new one. + // This is necessary since we have observed that in some cases + // Infinispan does aggregation for operations (eg:- remove and then put a different value) + // related to the same key within the same transaction. + // Need this defensive code as the new FlowEntryInstall may be different + // than the old one even though the equals method returns true. This is because + // the equals method does not take into account the action list. + if(nodeIndeces.contains(flowEntries)) { + nodeIndeces.remove(flowEntries); + } nodeIndeces.add(flowEntries); } else { nodeIndeces.remove(flowEntries); @@ -889,6 +903,11 @@ public class ForwardingRulesManager implements } if (add) { + // same comments in the similar code section in + // updateNodeFlowsDB method apply here too + if(indices.contains(flowEntries)) { + indices.remove(flowEntries); + } indices.add(flowEntries); } else { indices.remove(flowEntries); @@ -928,7 +947,7 @@ public class ForwardingRulesManager implements // Update DB if (status.isSuccess()) { - updateLocalDatabase(target, false); + updateSwViews(target, false); } else { // log the error log.trace("SDN Plugin failed to remove the flow: {}. The failure is: {}", target.getInstall(), @@ -1171,8 +1190,6 @@ public class ForwardingRulesManager implements private void nonClusterObjectCreate() { originalSwView = new ConcurrentHashMap(); installedSwView = new ConcurrentHashMap(); - nodeFlows = new ConcurrentHashMap>(); - groupFlows = new ConcurrentHashMap>(); TSPolicies = new ConcurrentHashMap(); staticFlowsOrdinal = new ConcurrentHashMap(); portGroupConfigs = new ConcurrentHashMap(); @@ -1181,11 +1198,6 @@ public class ForwardingRulesManager implements inactiveFlows = new ConcurrentHashMap(); } - private void registerWithOSGIConsole() { - BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); - bundleContext.registerService(CommandProvider.class.getName(), this, null); - } - @Override public void setTSPolicyData(String policyname, Object o, boolean add) { @@ -1230,7 +1242,7 @@ public class ForwardingRulesManager implements if (policyName != null && !policyName.trim().isEmpty()) { for (Map.Entry entry : this.originalSwView.entrySet()) { if (policyName.equals(entry.getKey().getGroupName())) { - list.add(entry.getKey().clone()); + list.add(entry.getValue().clone()); } } } @@ -1243,7 +1255,7 @@ public class ForwardingRulesManager implements if (policyName != null && !policyName.trim().isEmpty()) { for (Map.Entry entry : this.installedSwView.entrySet()) { if (policyName.equals(entry.getKey().getGroupName())) { - list.add(entry.getKey().getInstall().clone()); + list.add(entry.getValue().getInstall().clone()); } } } @@ -1262,7 +1274,7 @@ public class ForwardingRulesManager implements } Status error = modifyEntry(currentFlowEntry, newFlowEntry, false); if (error.isSuccess()) { - log.info("Ports {} added to FlowEntry {}", portList, flowName); + log.trace("Ports {} added to FlowEntry {}", portList, flowName); } else { log.warn("Failed to add ports {} to Flow entry {}. The failure is: {}", portList, currentFlowEntry.toString(), error.getDescription()); @@ -1286,7 +1298,7 @@ public class ForwardingRulesManager implements } Status status = modifyEntry(currentFlowEntry, newFlowEntry, false); if (status.isSuccess()) { - log.info("Ports {} removed from FlowEntry {}", portList, flowName); + log.trace("Ports {} removed from FlowEntry {}", portList, flowName); } else { log.warn("Failed to remove ports {} from Flow entry {}. The failure is: {}", portList, currentFlowEntry.toString(), status.getDescription()); @@ -1334,7 +1346,7 @@ public class ForwardingRulesManager implements Status status = modifyEntry(currentFlowEntry, newFlowEntry, false); if (status.isSuccess()) { - log.info("Output port replaced with {} for flow {} on node {}", outPort, flowName, node); + log.trace("Output port replaced with {} for flow {} on node {}", outPort, flowName, node); } else { log.warn("Failed to replace output port for flow {} on node {}. The failure is: {}", flowName, node, status.getDescription()); @@ -1371,21 +1383,15 @@ public class ForwardingRulesManager implements log.debug("Allocating caches for Container {}", container.getName()); try { - clusterContainerService.createCache("frm.originalSwView", + clusterContainerService.createCache(ORIGINAL_SW_VIEW_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); - clusterContainerService.createCache("frm.installedSwView", + clusterContainerService.createCache(INSTALLED_SW_VIEW_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); clusterContainerService.createCache("frm.inactiveFlows", EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); - clusterContainerService.createCache("frm.nodeFlows", - EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); - - clusterContainerService.createCache("frm.groupFlows", - EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); - clusterContainerService.createCache("frm.staticFlows", EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); @@ -1426,14 +1432,14 @@ public class ForwardingRulesManager implements log.debug("Retrieving Caches for Container {}", container.getName()); - map = clusterContainerService.getCache("frm.originalSwView"); + map = clusterContainerService.getCache(ORIGINAL_SW_VIEW_CACHE); if (map != null) { originalSwView = (ConcurrentMap) map; } else { log.error("Retrieval of frm.originalSwView cache failed for Container {}", container.getName()); } - map = clusterContainerService.getCache("frm.installedSwView"); + map = clusterContainerService.getCache(INSTALLED_SW_VIEW_CACHE); if (map != null) { installedSwView = (ConcurrentMap) map; } else { @@ -1447,20 +1453,6 @@ public class ForwardingRulesManager implements log.error("Retrieval of frm.inactiveFlows cache failed for Container {}", container.getName()); } - map = clusterContainerService.getCache("frm.nodeFlows"); - if (map != null) { - nodeFlows = (ConcurrentMap>) map; - } else { - log.error("Retrieval of cache failed for Container {}", container.getName()); - } - - map = clusterContainerService.getCache("frm.groupFlows"); - if (map != null) { - groupFlows = (ConcurrentMap>) map; - } else { - log.error("Retrieval of frm.groupFlows cache failed for Container {}", container.getName()); - } - map = clusterContainerService.getCache("frm.staticFlows"); if (map != null) { staticFlows = (ConcurrentMap) map; @@ -1658,7 +1650,7 @@ public class ForwardingRulesManager implements // Take note of this controller generated static flow toRemove.add(entry.getKey()); } else { - config.setStatus(NODEDOWN); + config.setStatus(NODE_DOWN); } } } @@ -1812,7 +1804,7 @@ public class ForwardingRulesManager implements // Do not attempt to reinstall the flow, warn user if (newFlowConfig.equals(oldFlowConfig)) { String msg = "No modification detected"; - log.info("Static flow modification skipped. New flow and old flow are the same: {}", newFlowConfig); + log.trace("Static flow modification skipped. New flow and old flow are the same: {}", newFlowConfig); return new Status(StatusCode.SUCCESS, msg); } @@ -1914,7 +1906,7 @@ public class ForwardingRulesManager implements * inactive list */ private void uninstallAllFlowEntries(boolean preserveFlowEntries) { - log.info("Uninstalling all non-internal flows"); + log.trace("Uninstalling all non-internal flows"); List toRemove = new ArrayList(); @@ -1952,7 +1944,7 @@ public class ForwardingRulesManager implements * default container instance of FRM only when the last container is deleted */ private void reinstallAllFlowEntries() { - log.info("Reinstalling all inactive flows"); + log.trace("Reinstalling all inactive flows"); for (FlowEntry flowEntry : this.inactiveFlows.keySet()) { this.addEntry(flowEntry, false); @@ -1964,22 +1956,7 @@ public class ForwardingRulesManager implements @Override public List getStaticFlows() { - return getStaticFlowsOrderedList(staticFlows, staticFlowsOrdinal.get(0).intValue()); - } - - // TODO: need to come out with a better algorithm for maintaining the order - // of the configuration entries - // with actual one, index associated to deleted entries cannot be reused and - // map grows... - private List getStaticFlowsOrderedList(ConcurrentMap flowMap, int maxKey) { - List orderedList = new ArrayList(); - for (int i = 0; i <= maxKey; i++) { - FlowConfig entry = flowMap.get(i); - if (entry != null) { - orderedList.add(entry); - } - } - return orderedList; + return new ArrayList(staticFlows.values()); } @Override @@ -2022,34 +1999,13 @@ public class ForwardingRulesManager implements return new ArrayList(set); } - @SuppressWarnings("unchecked") private void loadFlowConfiguration() { - ObjectReader objReader = new ObjectReader(); - ConcurrentMap confList = (ConcurrentMap) objReader.read(this, - frmFileName); - - ConcurrentMap pgConfig = (ConcurrentMap) objReader.read(this, - portGroupFileName); - - if (pgConfig != null) { - for (ConcurrentMap.Entry entry : pgConfig.entrySet()) { - addPortGroupConfig(entry.getKey(), entry.getValue().getMatchString(), true); - } + for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, PORT_GROUP_FILE_NAME)) { + addPortGroupConfig(((PortGroupConfig) conf).getName(), ((PortGroupConfig) conf).getMatchString(), true); } - if (confList == null) { - return; - } - - int maxKey = 0; - for (Integer key : confList.keySet()) { - if (key.intValue() > maxKey) { - maxKey = key.intValue(); - } - } - - for (FlowConfig conf : getStaticFlowsOrderedList(confList, maxKey)) { - addStaticFlowInternal(conf, true); + for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, STATIC_FLOWS_FILE_NAME)) { + addStaticFlowInternal((FlowConfig) conf, true); } } @@ -2064,25 +2020,44 @@ public class ForwardingRulesManager implements } private Status saveConfigInternal() { - ObjectWriter objWriter = new ObjectWriter(); - ConcurrentMap nonDynamicFlows = new ConcurrentHashMap(); + List nonDynamicFlows = new ArrayList(); + for (Integer ordinal : staticFlows.keySet()) { FlowConfig config = staticFlows.get(ordinal); // Do not save dynamic and controller generated static flows if (config.isDynamic() || config.isInternalFlow()) { continue; } - nonDynamicFlows.put(ordinal, config); + nonDynamicFlows.add(config); } - objWriter.write(nonDynamicFlows, frmFileName); - objWriter.write(new ConcurrentHashMap(portGroupConfigs), portGroupFileName); - return new Status(StatusCode.SUCCESS, null); + + configurationService.persistConfiguration(nonDynamicFlows, STATIC_FLOWS_FILE_NAME); + configurationService.persistConfiguration(new ArrayList(portGroupConfigs.values()), + PORT_GROUP_FILE_NAME); + + return new Status(StatusCode.SUCCESS); } @Override public void subnetNotify(Subnet sub, boolean add) { } + private boolean programInternalFlow(boolean proactive, FlowConfig fc) { + boolean retVal = true; // program flows unless determined otherwise + if(proactive) { + // if the flow already exists do not program + if(flowConfigExists(fc)) { + retVal = false; + } + } else { + // if the flow does not exist do not program + if(!flowConfigExists(fc)) { + retVal = false; + } + } + return retVal; + } + /** * (non-Javadoc) * @@ -2137,14 +2112,20 @@ public class ForwardingRulesManager implements dropAllConfig.setActions(dropAction); defaultConfigs.add(dropAllConfig); - log.info("Forwarding mode for node {} set to {}", node, (proactive ? "proactive" : "reactive")); + log.trace("Forwarding mode for node {} set to {}", node, (proactive ? "proactive" : "reactive")); for (FlowConfig fc : defaultConfigs) { - Status status = (proactive) ? addStaticFlowInternal(fc, false) : removeStaticFlow(fc); - if (status.isSuccess()) { - log.info("{} Proactive Static flow: {}", (proactive ? "Installed" : "Removed"), fc.getName()); + // check if the frm really needs to act on the notification. + // this is to check against duplicate notifications + if(programInternalFlow(proactive, fc)) { + Status status = (proactive) ? addStaticFlowInternal(fc, false) : removeStaticFlow(fc); + if (status.isSuccess()) { + log.trace("{} Proactive Static flow: {}", (proactive ? "Installed" : "Removed"), fc.getName()); + } else { + log.warn("Failed to {} Proactive Static flow: {}", (proactive ? "install" : "remove"), + fc.getName()); + } } else { - log.warn("Failed to {} Proactive Static flow: {}", (proactive ? "install" : "remove"), - fc.getName()); + log.debug("Got redundant install request for internal flow: {} on node: {}. Request not sent to FRM.", fc.getName(), node); } } return new Status(StatusCode.SUCCESS); @@ -2164,12 +2145,12 @@ public class ForwardingRulesManager implements * @param node */ private void cleanDatabaseForNode(Node node) { - log.info("Cleaning Flow database for Node {}", node); + log.trace("Cleaning Flow database for Node {}", node); if (nodeFlows.containsKey(node)) { List toRemove = new ArrayList(nodeFlows.get(node)); for (FlowEntryInstall entry : toRemove) { - updateLocalDatabase(entry, false); + updateSwViews(entry, false); } } } @@ -2293,7 +2274,7 @@ public class ForwardingRulesManager implements if (fei.getGroupName().equals(FlowConfig.STATICFLOWGROUP)) { FlowConfig flowConfig = getStaticFlow(fei.getFlowName(), fei.getNode()); if (flowConfig != null) { - flowConfig.setStatus(PORTREMOVED); + flowConfig.setStatus(PORT_REMOVED); updated = true; } } @@ -2341,7 +2322,7 @@ public class ForwardingRulesManager implements @Override public void portGroupChanged(PortGroupConfig config, Map data, boolean add) { - log.info("PortGroup Changed for: {} Data: {}", config, portGroupData); + log.trace("PortGroup Changed for: {} Data: {}", config, portGroupData); Map existingData = portGroupData.get(config); if (existingData != null) { for (Map.Entry entry : data.entrySet()) { @@ -2429,6 +2410,16 @@ public class ForwardingRulesManager implements } } + public void setConfigurationContainerService(IConfigurationContainerService service) { + log.trace("Got configuration service set request {}", service); + this.configurationService = service; + } + + public void unsetConfigurationContainerService(IConfigurationContainerService service) { + log.trace("Got configuration service UNset request"); + this.configurationService = null; + } + @Override public PortGroupProvider getPortGroupProvider() { return portGroupProvider; @@ -2479,8 +2470,6 @@ public class ForwardingRulesManager implements * */ void init() { - frmFileName = GlobalConstants.STARTUPHOME.toString() + "frm_staticflows_" + this.getContainerName() + ".conf"; - portGroupFileName = GlobalConstants.STARTUPHOME.toString() + "portgroup_" + this.getContainerName() + ".conf"; inContainerMode = false; @@ -2488,9 +2477,10 @@ public class ForwardingRulesManager implements portGroupProvider.registerPortGroupChange(this); } - cacheStartup(); + nodeFlows = new ConcurrentHashMap>(); + groupFlows = new ConcurrentHashMap>(); - registerWithOSGIConsole(); + cacheStartup(); /* * If we are not the first cluster node to come up, do not initialize @@ -2546,13 +2536,13 @@ public class ForwardingRulesManager implements FlowEntryInstall feiNew = workOrder.get(fe); switch (fe.getUpType()) { case ADDED: - gotStatus = addEntriesInternal(feiCurrent, false); + gotStatus = addEntryInHw(feiCurrent, false); break; case CHANGED: - gotStatus = modifyEntryInternal(feiCurrent, feiNew, false); + gotStatus = modifyEntryInHw(feiCurrent, feiNew, false); break; case REMOVED: - gotStatus = removeEntryInternal(feiCurrent, false); + gotStatus = removeEntryInHw(feiCurrent, false); break; } // Remove the Order @@ -2589,9 +2579,11 @@ public class ForwardingRulesManager implements * flow merging is not an injective function */ updateFlowsContainerFlow(); + } else if (event instanceof UpdateIndexDBs) { + UpdateIndexDBs update = (UpdateIndexDBs)event; + updateIndexDatabase(update.getFei(), update.isAddition()); } else { - log.warn("Dequeued unknown event {}", event.getClass() - .getSimpleName()); + log.warn("Dequeued unknown event {}", event.getClass().getSimpleName()); } } catch (InterruptedException e) { // clear pending events @@ -2640,13 +2632,23 @@ public class ForwardingRulesManager implements // Start event handler thread frmEventHandler.start(); + // replay the installedSwView data structure to populate + // node flows and group flows + for (FlowEntryInstall fei : installedSwView.values()) { + pendingEvents.offer(new UpdateIndexDBs(fei, true)); + } + /* - * Read startup and build database if we have not already gotten the - * configurations synced from another node + * Read startup and build database if we are the coordinator */ - if (staticFlows.isEmpty()) { - loadFlowConfiguration(); - } + loadFlowConfiguration(); + } + + /** + * Function called by the dependency manager before Container is Stopped and Destroyed. + */ + public void containerStop() { + uninstallAllFlowEntries(false); } /** @@ -2656,7 +2658,6 @@ public class ForwardingRulesManager implements */ void stop() { stopping = true; - uninstallAllFlowEntries(false); // Shutdown executor this.executor.shutdownNow(); // Now walk all the workMonitor and wake up the one sleeping because @@ -2878,100 +2879,41 @@ public class ForwardingRulesManager implements } } - /* - * OSGI COMMANDS - */ - @Override - public String getHelp() { - StringBuffer help = new StringBuffer(); - return help.toString(); - } + private class UpdateIndexDBs extends FRMEvent { + private FlowEntryInstall fei; + private boolean add; - @Override - public Status saveConfiguration() { - return saveConfig(); - } - - public void _frmNodeFlows(CommandInterpreter ci) { - String nodeId = ci.nextArgument(); - Node node = Node.fromString(nodeId); - if (node == null) { - ci.println("frmNodeFlows [verbose]"); - return; - } - boolean verbose = false; - String verboseCheck = ci.nextArgument(); - if (verboseCheck != null) { - verbose = verboseCheck.equals("true"); + /** + * + * @param fei the flow entry which was installed/removed on the netwrok node + * @param update + */ + UpdateIndexDBs(FlowEntryInstall fei, boolean add) { + this.fei = fei; + this.add = add; } - if (!nodeFlows.containsKey(node)) { - return; - } - // Dump per node database - for (FlowEntryInstall entry : nodeFlows.get(node)) { - if (!verbose) { - ci.println(node + " " + installedSwView.get(entry).getFlowName()); - } else { - ci.println(node + " " + installedSwView.get(entry).toString()); - } - } - } - public void _frmGroupFlows(CommandInterpreter ci) { - String group = ci.nextArgument(); - if (group == null) { - ci.println("frmGroupFlows [verbose]"); - return; - } - boolean verbose = false; - String verboseCheck = ci.nextArgument(); - if (verboseCheck != null) { - verbose = verboseCheck.equalsIgnoreCase("true"); + /** + * @return the flowEntryInstall object which was added/removed + * to/from the installed software view cache + */ + public FlowEntryInstall getFei() { + return fei; } - if (!groupFlows.containsKey(group)) { - return; - } - // Dump per node database - ci.println("Group " + group + ":\n"); - for (FlowEntryInstall flowEntry : groupFlows.get(group)) { - if (!verbose) { - ci.println(flowEntry.getNode() + " " + flowEntry.getFlowName()); - } else { - ci.println(flowEntry.getNode() + " " + flowEntry.toString()); - } + /** + * + * @return whether this was an flow addition or removal + */ + public boolean isAddition() { + return add; } } - public void _frmProcessErrorEvent(CommandInterpreter ci) throws UnknownHostException { - Node node = null; - long reqId = 0L; - String nodeId = ci.nextArgument(); - if (nodeId == null) { - ci.print("Node id not specified"); - return; - } - String requestId = ci.nextArgument(); - if (requestId == null) { - ci.print("Request id not specified"); - return; - } - try { - node = NodeCreator.createOFNode(Long.valueOf(nodeId)); - } catch (NumberFormatException e) { - ci.print("Node id not a number"); - return; - } - try { - reqId = Long.parseLong(requestId); - } catch (NumberFormatException e) { - ci.print("Request id not a number"); - return; - } - // null for error object is good enough for now - ErrorReportedEvent event = new ErrorReportedEvent(reqId, node, null); - this.processErrorEvent(event); + @Override + public Status saveConfiguration() { + return saveConfig(); } @Override @@ -2999,13 +2941,21 @@ public class ForwardingRulesManager implements } if (target != null) { // Update Configuration database - target.toggleInstallation(); - target.setStatus(StatusCode.SUCCESS.toString()); + if (target.getHardTimeout() != null || target.getIdleTimeout() != null) { + /* + * No need for checking if actual values: these strings were + * validated at configuration creation. Also, after a switch + * down scenario, no use to reinstall a timed flow. Mark it as + * "do not install". User can manually toggle it. + */ + target.toggleInstallation(); + } + target.setStatus(StatusCode.GONE.toString()); staticFlows.put(key, target); } // Update software views - this.updateLocalDatabase(installedEntry, false); + this.updateSwViews(installedEntry, false); } @Override @@ -3042,14 +2992,18 @@ public class ForwardingRulesManager implements } if (target != null) { // This was a flow install, update database - this.updateLocalDatabase(target, false); + this.updateSwViews(target, false); // also update the config if(FlowConfig.STATICFLOWGROUP.equals(target.getGroupName())) { ConcurrentMap.Entry staticFlowEntry = getStaticFlowEntry(target.getFlowName(),target.getNode()); // staticFlowEntry should never be null. // the null check is just an extra defensive check. if(staticFlowEntry != null) { - staticFlows.remove(staticFlowEntry.getKey()); + // Modify status and update cluster cache + log.debug("Updating static flow configuration on async error event"); + String status = String.format("Cannot be installed on node. reason: %s", errorString); + staticFlowEntry.getValue().setStatus(status); + refreshClusterStaticFlowsStatus(node); } } } @@ -3112,6 +3066,13 @@ public class ForwardingRulesManager implements @Override public void entryUpdated(Object key, Object new_value, String cacheName, boolean originLocal) { + /* + * Streamline the updates for the per node and per group index databases + */ + if (cacheName.equals(INSTALLED_SW_VIEW_CACHE)) { + pendingEvents.offer(new UpdateIndexDBs((FlowEntryInstall)new_value, true)); + } + if (originLocal) { /* * Local updates are of no interest @@ -3163,8 +3124,11 @@ public class ForwardingRulesManager implements @Override public void entryDeleted(Object key, String cacheName, boolean originLocal) { /* - * Do nothing + * Streamline the updates for the per node and per group index databases */ + if (cacheName.equals(INSTALLED_SW_VIEW_CACHE)) { + pendingEvents.offer(new UpdateIndexDBs((FlowEntryInstall)key, false)); + } } /** @@ -3176,7 +3140,7 @@ public class ForwardingRulesManager implements if (node != null) { for (Map.Entry entry : this.originalSwView.entrySet()) { if (node.equals(entry.getKey().getNode())) { - list.add(entry.getKey().clone()); + list.add(entry.getValue().clone()); } } }