X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fforwardingrulesmanager%2Fimplementation%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fforwardingrulesmanager%2Finternal%2FForwardingRulesManager.java;h=f7b647dd721a1f1f9117d95bc3723867574e5064;hp=2b3347f312469b00ca6748f5d19884626ce1daf3;hb=e8b8890b47b54a15de876ab63f41bae6eac61120;hpb=64dfe060369551b2f011889a7e77844bf35ce01a 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 2b3347f312..f7b647dd72 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 @@ -33,7 +33,9 @@ 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; @@ -48,6 +50,9 @@ import org.opendaylight.controller.forwardingrulesmanager.PortGroupProvider; import org.opendaylight.controller.forwardingrulesmanager.implementation.data.FlowEntryDistributionOrder; import org.opendaylight.controller.sal.action.Action; import org.opendaylight.controller.sal.action.ActionType; +import org.opendaylight.controller.sal.action.Enqueue; +import org.opendaylight.controller.sal.action.Flood; +import org.opendaylight.controller.sal.action.FloodAll; import org.opendaylight.controller.sal.action.Output; import org.opendaylight.controller.sal.connection.ConnectionLocality; import org.opendaylight.controller.sal.core.Config; @@ -66,8 +71,6 @@ 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.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; @@ -98,14 +101,15 @@ public class ForwardingRulesManager implements 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; @@ -242,6 +246,57 @@ public class ForwardingRulesManager implements return null; } + /** + * Checks if the FlowEntry targets are valid for this container + * + * @param flowEntry + * The flow entry to test + * @return a Status object representing the result of the validation + */ + private Status validateEntry(FlowEntry flowEntry) { + // Node presence check + Node node = flowEntry.getNode(); + if (!switchManager.getNodes().contains(node)) { + return new Status(StatusCode.BADREQUEST, String.format("Node %s is not present in this container", node)); + } + + // Ports and actions validation check + Flow flow = flowEntry.getFlow(); + Match match = flow.getMatch(); + if (match.isPresent(MatchType.IN_PORT)) { + NodeConnector inputPort = (NodeConnector)match.getField(MatchType.IN_PORT).getValue(); + if (!switchManager.getNodeConnectors(node).contains(inputPort)) { + String msg = String.format("Ingress port %s is not present on this container", inputPort); + return new Status(StatusCode.BADREQUEST, msg); + } + } + for (Action action : flow.getActions()) { + if (action instanceof Flood && !GlobalConstants.DEFAULT.toString().equals(getContainerName())) { + return new Status(StatusCode.BADREQUEST, String.format("Flood is only allowed in default container")); + } + if (action instanceof FloodAll && !GlobalConstants.DEFAULT.toString().equals(getContainerName())) { + return new Status(StatusCode.BADREQUEST, String.format("FloodAll is only allowed in default container")); + } + if (action instanceof Output) { + Output out = (Output)action; + NodeConnector outputPort = out.getPort(); + if (!switchManager.getNodeConnectors(node).contains(outputPort)) { + String msg = String.format("Output port %s is not present on this container", outputPort); + return new Status(StatusCode.BADREQUEST, msg); + } + } + if (action instanceof Enqueue) { + Enqueue out = (Enqueue)action; + NodeConnector outputPort = out.getPort(); + if (!switchManager.getNodeConnectors(node).contains(outputPort)) { + String msg = String.format("Enqueue port %s is not present on this container", outputPort); + return new Status(StatusCode.BADREQUEST, msg); + } + } + } + return new Status(StatusCode.SUCCESS); + } + /** * Adds a flow entry onto the network node It runs various validity checks * and derive the final container flows merged entries that will be @@ -263,6 +318,15 @@ public class ForwardingRulesManager implements return new Status(StatusCode.NOTACCEPTABLE, INVALID_FLOW_ENTRY); } + // Operational check: input, output and queue ports presence check and + // action validation for this container + Status status = validateEntry(flowEntry); + if (!status.isSuccess()) { + String msg = String.format("%s: %s", INVALID_FLOW_ENTRY, status.getDescription()); + log.warn("{}: {}", msg, flowEntry); + return new Status(StatusCode.NOTACCEPTABLE, msg); + } + /* * Redundant Check: Check if the request is a redundant one from the * same application the flowEntry is equal to an existing one. Given we @@ -330,7 +394,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; @@ -421,6 +485,15 @@ public class ForwardingRulesManager implements return new Status(StatusCode.SUCCESS, msg); } + // Operational check: input, output and queue ports presence check and + // action validation for this container + Status status = validateEntry(newFlowEntry); + if (!status.isSuccess()) { + String msg = String.format("Modify: %s: %s", INVALID_FLOW_ENTRY, status.getDescription()); + log.warn("{}: {}", msg, newFlowEntry); + return new Status(StatusCode.NOTACCEPTABLE, msg); + } + /* * Conflict Check: Verify the new entry would not conflict with an * existing one. This is a loose check on the previous original flow @@ -467,7 +540,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; } @@ -479,7 +552,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); @@ -493,7 +566,7 @@ public class ForwardingRulesManager implements } // Install new entries for (FlowEntryInstall newEntry : toInstallSafe) { - succeeded = this.addEntriesInternal(newEntry, async); + succeeded = this.addEntryInternal(newEntry, async); } } else { /* @@ -553,7 +626,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 @@ -563,13 +638,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()); @@ -579,30 +654,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()); - updateSwViews(currentEntries, false); - updateSwViews(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()); } /** @@ -671,6 +747,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 @@ -680,13 +758,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()); } @@ -695,28 +772,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 - updateSwViews(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()); } /** @@ -724,6 +804,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 @@ -732,14 +814,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()); } @@ -748,27 +829,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()); - updateSwViews(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()); } /** @@ -1110,7 +1193,10 @@ public class ForwardingRulesManager implements List list = new ArrayList(groupFlows.get(groupName)); toBeRemoved = list.size(); for (FlowEntryInstall entry : list) { - Status status = this.removeEntry(entry.getOriginal(), false); + // since this is the entry that was stored in groupFlows + // it is already validated and merged + // so can call removeEntryInternal directly + Status status = this.removeEntryInternal(entry, false); if (status.isSuccess()) { toBeRemoved -= 1; } else { @@ -1263,7 +1349,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()); @@ -1287,7 +1373,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()); @@ -1335,7 +1421,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()); @@ -1504,15 +1590,25 @@ public class ForwardingRulesManager implements @Override public Status addStaticFlow(FlowConfig config) { + return addStaticFlow(config, false); + } + + private Status addStaticFlow(FlowConfig config, boolean async) { // Configuration object validation - Status status = config.validate(container); + Status status = config.validate(); if (!status.isSuccess()) { log.warn("Invalid Configuration for flow {}. The failure is {}", config, status.getDescription()); String error = "Invalid Configuration (" + status.getDescription() + ")"; config.setStatus(error); return new Status(StatusCode.BADREQUEST, error); } - return addStaticFlowInternal(config, false); + return addStaticFlowInternal(config, async, false); + } + + + @Override + public Status addStaticFlowAsync(FlowConfig config) { + return addStaticFlow(config, true); } /** @@ -1530,7 +1626,7 @@ public class ForwardingRulesManager implements * installation on the network node was successful * @return The status of this request */ - private Status addStaticFlowInternal(FlowConfig config, boolean restore) { + private Status addStaticFlowInternal(FlowConfig config, boolean async, boolean restore) { boolean multipleFlowPush = false; String error; Status status; @@ -1567,7 +1663,7 @@ public class ForwardingRulesManager implements // Program hw if (config.installInHw()) { FlowEntry entry = config.getFlowEntry(); - status = this.installFlowEntry(entry); + status = async ? this.installFlowEntryAsync(entry) : this.installFlowEntry(entry); if (!status.isSuccess()) { config.setStatus(status.getDescription()); if (!restore) { @@ -1669,6 +1765,7 @@ public class ForwardingRulesManager implements config.setStatus(StatusCode.SUCCESS.toString()); break; default: + break; } } } @@ -1678,6 +1775,15 @@ public class ForwardingRulesManager implements @Override public Status removeStaticFlow(FlowConfig config) { + return removeStaticFlow(config, false); + } + + @Override + public Status removeStaticFlowAsync(FlowConfig config) { + return removeStaticFlow(config, true); + } + + private Status removeStaticFlow(FlowConfig config, boolean async) { /* * 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 @@ -1701,7 +1807,8 @@ public class ForwardingRulesManager implements } // Program the network node - Status status = this.uninstallFlowEntry(config.getFlowEntry()); + Status status = async ? this.uninstallFlowEntryAsync(config.getFlowEntry()) : this.uninstallFlowEntry(config + .getFlowEntry()); // Update configuration database if programming was successful if (status.isSuccess()) { @@ -1713,6 +1820,15 @@ public class ForwardingRulesManager implements @Override public Status removeStaticFlow(String name, Node node) { + return removeStaticFlow(name, node, false); + } + + @Override + public Status removeStaticFlowAsync(String name, Node node) { + return removeStaticFlow(name, node, true); + } + + private Status removeStaticFlow(String name, Node node, boolean async) { // Look for the target configuration entry Integer key = 0; FlowConfig target = null; @@ -1743,7 +1859,7 @@ public class ForwardingRulesManager implements } // Program the network node - Status status = this.removeEntry(target.getFlowEntry(), false); + Status status = this.removeEntry(target.getFlowEntry(), async); // Update configuration database if programming was successful if (status.isSuccess()) { @@ -1764,7 +1880,7 @@ public class ForwardingRulesManager implements } // Validity Check - Status status = newFlowConfig.validate(container); + Status status = newFlowConfig.validate(); if (!status.isSuccess()) { String msg = "Invalid Configuration (" + status.getDescription() + ")"; newFlowConfig.setStatus(msg); @@ -1793,7 +1909,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); } @@ -1844,7 +1960,7 @@ public class ForwardingRulesManager implements } } if (target != null) { - Status status = target.validate(container); + Status status = target.validate(); if (!status.isSuccess()) { log.warn(status.getDescription()); return status; @@ -1895,7 +2011,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(); @@ -1933,7 +2049,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); @@ -1945,22 +2061,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 @@ -2003,34 +2104,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, false, true); } } @@ -2045,25 +2125,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) * @@ -2118,14 +2217,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, 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); @@ -2145,7 +2250,7 @@ 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)); @@ -2300,7 +2405,7 @@ public class ForwardingRulesManager implements if ((staticFlow.getNode().equals(node)) && (staticFlow.getPortGroup().equals(config.getName()))) { for (Short port : data.getPorts()) { FlowConfig derivedFlow = getDerivedFlowConfig(staticFlow, config.getName(), port); - addStaticFlowInternal(derivedFlow, false); + addStaticFlowInternal(derivedFlow, false, false); } } } @@ -2322,7 +2427,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()) { @@ -2410,6 +2515,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; @@ -2460,8 +2575,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; @@ -2528,13 +2641,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 @@ -2631,12 +2744,9 @@ public class ForwardingRulesManager implements } /* - * 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(); } /** @@ -2752,6 +2862,7 @@ public class ForwardingRulesManager implements this.reinstallAllFlowEntries(); break; default: + break; } // Update our configuration DB @@ -2994,7 +3105,11 @@ public class ForwardingRulesManager implements // 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); } } } @@ -3154,4 +3269,5 @@ public class ForwardingRulesManager implements } return list; } + }