X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fswitchmanager%2Fimplementation%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fswitchmanager%2Finternal%2FSwitchManager.java;h=217b8d46904aad44eee3ed399b2651d77826da0e;hb=e18b0fd6a43fb909f5548e6a9130ddf7654beef0;hp=1390f94b494c423198abde7736b4e77f965046d0;hpb=0e4d6083e5d4f7b22e909f86f9471f981d7ca8f3;p=controller.git diff --git a/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java b/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java index 1390f94b49..8372f88e7d 100644 --- a/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java +++ b/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java @@ -12,13 +12,10 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; import java.util.ArrayList; import java.util.Collections; import java.util.Dictionary; import java.util.EnumSet; -import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -35,7 +32,9 @@ import org.opendaylight.controller.clustering.services.CacheConfigException; import org.opendaylight.controller.clustering.services.CacheExistException; 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.sal.core.Bandwidth; import org.opendaylight.controller.sal.core.Config; import org.opendaylight.controller.sal.core.ConstructionException; @@ -54,10 +53,8 @@ import org.opendaylight.controller.sal.inventory.IInventoryService; import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates; import org.opendaylight.controller.sal.reader.NodeDescription; import org.opendaylight.controller.sal.utils.GlobalConstants; -import org.opendaylight.controller.sal.utils.HexEncode; 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.ServiceHelper; import org.opendaylight.controller.sal.utils.Status; import org.opendaylight.controller.sal.utils.StatusCode; import org.opendaylight.controller.statisticsmanager.IStatisticsManager; @@ -86,8 +83,9 @@ import org.slf4j.LoggerFactory; public class SwitchManager implements ISwitchManager, IConfigurationContainerAware, IObjectReader, IListenInventoryUpdates, CommandProvider { private static Logger log = LoggerFactory.getLogger(SwitchManager.class); - private static String ROOT = GlobalConstants.STARTUPHOME.toString(); - private String subnetFileName, spanFileName, switchConfigFileName; + private static final String SUBNETS_FILE_NAME = "subnets.conf"; + private static final String SPAN_FILE_NAME = "spanPorts.conf"; + private static final String SWITCH_CONFIG_FILE_NAME = "switchConfig.conf"; private final List spanNodeConnectors = new CopyOnWriteArrayList(); // Collection of Subnets keyed by the InetAddress private ConcurrentMap subnets; @@ -101,18 +99,34 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa private ConcurrentMap controllerProps; private IInventoryService inventoryService; private IStatisticsManager statisticsManager; + private IControllerProperties controllerProperties; + private IConfigurationContainerService configurationService; private final Set switchManagerAware = Collections .synchronizedSet(new HashSet()); private final Set inventoryListeners = Collections .synchronizedSet(new HashSet()); private final Set spanAware = Collections.synchronizedSet(new HashSet()); - private static boolean hostRefresh = true; - private int hostRetryCount = 5; private IClusterContainerServices clusterContainerService = null; private String containerName = null; private boolean isDefaultContainer = true; private static final int REPLACE_RETRY = 1; + /* Information about the default subnet. If there have been no configured subnets, i.e., + * subnets.size() == 0 or subnetsConfigList.size() == 0, then this subnet will be the + * only subnet returned. As soon as a user-configured subnet is created this one will + * vanish. + */ + private static final String DISABLE_DEFAULT_SUBNET_PROP = "switchmanager.disableDefaultSubnetGateway"; + private static final String DISABLE_DEFAULT_SUBNET_PROP_VAL = System.getProperty(DISABLE_DEFAULT_SUBNET_PROP); + private static final boolean USE_DEFAULT_SUBNET_GW = !Boolean.valueOf(DISABLE_DEFAULT_SUBNET_PROP_VAL); + protected static final SubnetConfig DEFAULT_SUBNETCONFIG; + protected static final Subnet DEFAULT_SUBNET; + protected static final String DEFAULT_SUBNET_NAME = "default (cannot be modifed)"; + static{ + DEFAULT_SUBNETCONFIG = new SubnetConfig(DEFAULT_SUBNET_NAME, "0.0.0.0/0", new ArrayList()); + DEFAULT_SUBNET = new Subnet(DEFAULT_SUBNETCONFIG); + } + public void notifySubnetChange(Subnet sub, boolean add) { synchronized (switchManagerAware) { for (Object subAware : switchManagerAware) { @@ -153,38 +167,18 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa } public void startUp() { - String container = this.getContainerName(); - // Initialize configuration file names - subnetFileName = ROOT + "subnets_" + container + ".conf"; - spanFileName = ROOT + "spanPorts_" + container + ".conf"; - switchConfigFileName = ROOT + "switchConfig_" + container + ".conf"; - // Instantiate cluster synced variables allocateCaches(); retrieveCaches(); - /* - * Read startup and build database if we have not already gotten the - * configurations synced from another node - */ - if (subnetsConfigList.isEmpty()) { - loadSubnetConfiguration(); - } - if (spanConfigList.isEmpty()) { - loadSpanConfiguration(); - } - if (nodeConfigList.isEmpty()) { - loadSwitchConfiguration(); - } - // Add controller MAC, if first node in the cluster - if (!controllerProps.containsKey(MacAddress.name)) { - byte controllerMac[] = getHardwareMAC(); + if ((!controllerProps.containsKey(MacAddress.name)) && (controllerProperties != null)) { + Property controllerMac = controllerProperties.getControllerProperty(MacAddress.name); if (controllerMac != null) { - Property existing = controllerProps.putIfAbsent(MacAddress.name, new MacAddress(controllerMac)); + Property existing = controllerProps.putIfAbsent(MacAddress.name, controllerMac); if (existing == null && log.isTraceEnabled()) { - log.trace("Container {}: Setting controller MAC address in the cluster: {}", container, - HexEncode.bytesToHexStringFormat(controllerMac)); + log.trace("Container {}: Setting controller MAC address in the cluster: {}", getContainerName(), + controllerMac); } } } @@ -193,7 +187,6 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa public void shutDown() { } - @SuppressWarnings("deprecation") private void allocateCaches() { if (this.clusterContainerService == null) { this.nonClusterObjectCreate(); @@ -211,9 +204,6 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); clusterContainerService.createCache("switchmanager.subnets", EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); - clusterContainerService.createCache( - "switchmanager.configSaveEvent", - EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); clusterContainerService.createCache("switchmanager.nodeProps", EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); clusterContainerService.createCache( @@ -232,10 +222,10 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa } } - @SuppressWarnings({ "unchecked", "deprecation" }) + @SuppressWarnings({ "unchecked" }) private void retrieveCaches() { if (this.clusterContainerService == null) { - log.info("un-initialized clusterContainerService, can't create cache"); + log.warn("un-initialized clusterContainerService, can't create cache"); return; } @@ -301,12 +291,22 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa @Override public List getSubnetsConfigList() { - return new ArrayList(subnetsConfigList.values()); + // if there are no subnets, return the default subnet + if (USE_DEFAULT_SUBNET_GW && subnetsConfigList.isEmpty()) { + return Collections.singletonList(DEFAULT_SUBNETCONFIG); + } else { + return new ArrayList(subnetsConfigList.values()); + } } @Override public SubnetConfig getSubnetConfig(String subnet) { - return subnetsConfigList.get(subnet); + // if there are no subnets, return the default subnet + if (USE_DEFAULT_SUBNET_GW && subnetsConfigList.isEmpty() && subnet.equalsIgnoreCase(DEFAULT_SUBNET_NAME)) { + return DEFAULT_SUBNETCONFIG; + } else { + return subnetsConfigList.get(subnet); + } } private List getSpanConfigList(Node node) { @@ -353,14 +353,10 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa @Override public List getNetworkDevices() { - Set nodeSet = getNodes(); List swList = new ArrayList(); - if (nodeSet != null) { - for (Node node : nodeSet) { - swList.add(getSwitchByNode(node)); - } + for (Node node : getNodes()) { + swList.add(getSwitchByNode(node)); } - return swList; } @@ -378,7 +374,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa private Status updateDatabase(SubnetConfig conf, boolean add) { if (add) { - Subnet subnetCurr = subnets.get(conf.getIPnum()); + Subnet subnetCurr = subnets.get(conf.getIPAddress()); Subnet subnet; if (subnetCurr == null) { subnet = new Subnet(conf); @@ -388,78 +384,90 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa // In case of API3 call we may receive the ports along with the // subnet creation if (!conf.isGlobal()) { - Set sp = conf.getSubnetNodeConnectors(); - subnet.addNodeConnectors(sp); + subnet.addNodeConnectors(conf.getNodeConnectors()); } boolean putNewSubnet = false; if(subnetCurr == null) { - if(subnets.putIfAbsent(conf.getIPnum(), subnet) == null) { + if(subnets.putIfAbsent(conf.getIPAddress(), subnet) == null) { putNewSubnet = true; } } else { - putNewSubnet = subnets.replace(conf.getIPnum(), subnetCurr, subnet); + putNewSubnet = subnets.replace(conf.getIPAddress(), subnetCurr, subnet); } if(!putNewSubnet) { - String msg = "Cluster conflict: Conflict while adding the subnet " + conf.getIPnum(); + String msg = "Cluster conflict: Conflict while adding the subnet " + conf.getIPAddress(); return new Status(StatusCode.CONFLICT, msg); } // Subnet removal case } else { - subnets.remove(conf.getIPnum()); + subnets.remove(conf.getIPAddress()); } return new Status(StatusCode.SUCCESS); } private Status semanticCheck(SubnetConfig conf) { - Subnet newSubnet = new Subnet(conf); Set IPs = subnets.keySet(); if (IPs == null) { return new Status(StatusCode.SUCCESS); } + Subnet newSubnet = new Subnet(conf); for (InetAddress i : IPs) { Subnet existingSubnet = subnets.get(i); - if ((existingSubnet != null) - && !existingSubnet.isMutualExclusive(newSubnet)) { - return new Status(StatusCode.CONFLICT); + if ((existingSubnet != null) && !existingSubnet.isMutualExclusive(newSubnet)) { + return new Status(StatusCode.CONFLICT, "This subnet conflicts with an existing one."); } } return new Status(StatusCode.SUCCESS); } private Status addRemoveSubnet(SubnetConfig conf, boolean isAdding) { - // Valid config check - if (!conf.isValidConfig()) { - String msg = "Invalid Subnet configuration"; - log.warn(msg); - return new Status(StatusCode.BADREQUEST, msg); + // Valid configuration check + Status status = conf.validate(); + if (!status.isSuccess()) { + log.warn(status.getDescription()); + return status; } if (isAdding) { // Presence check if (subnetsConfigList.containsKey(conf.getName())) { return new Status(StatusCode.CONFLICT, - "Subnet with the specified name already configured."); + "Subnet with the specified name already exists."); } // Semantic check - Status rc = semanticCheck(conf); - if (!rc.isSuccess()) { - return rc; + status = semanticCheck(conf); + if (!status.isSuccess()) { + return status; + } + } else { + if (conf.getName().equalsIgnoreCase(DEFAULT_SUBNET_NAME)) { + return new Status(StatusCode.NOTALLOWED, "The specified subnet gateway cannot be removed"); } } // Update Database - Status rc = updateDatabase(conf, isAdding); + status = updateDatabase(conf, isAdding); - if (rc.isSuccess()) { + if (status.isSuccess()) { // Update Configuration - rc = updateConfig(conf, isAdding); - if(!rc.isSuccess()) { + status = updateConfig(conf, isAdding); + if(!status.isSuccess()) { updateDatabase(conf, (!isAdding)); + } else { + // update the listeners + Subnet subnetCurr = subnets.get(conf.getIPAddress()); + Subnet subnet; + if (subnetCurr == null) { + subnet = new Subnet(conf); + } else { + subnet = subnetCurr.clone(); + } + notifySubnetChange(subnet, isAdding); } } - return rc; + return status; } /** @@ -477,6 +485,9 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa @Override public Status removeSubnet(String name) { + if (name.equalsIgnoreCase(DEFAULT_SUBNET_NAME)) { + return new Status(StatusCode.NOTALLOWED, "The specified subnet gateway cannot be removed"); + } SubnetConfig conf = subnetsConfigList.get(name); if (conf == null) { return new Status(StatusCode.SUCCESS, "Subnet not present"); @@ -485,26 +496,100 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa } @Override - public Status addPortsToSubnet(String name, String switchPorts) { + public Status modifySubnet(SubnetConfig conf) { + // Sanity check + if (conf == null) { + return new Status(StatusCode.BADREQUEST, "Invalid Subnet configuration: null"); + } + + // Valid configuration check + Status status = conf.validate(); + if (!status.isSuccess()) { + log.warn(status.getDescription()); + return status; + } + + // If a subnet configuration with this name does not exist, consider this is a creation + SubnetConfig target = subnetsConfigList.get(conf.getName()); + if (target == null) { + return this.addSubnet(conf); + } + + // No change + if (target.equals(conf)) { + return new Status(StatusCode.SUCCESS); + } + + // Check not allowed modifications + if (!target.getSubnet().equals(conf.getSubnet())) { + return new Status(StatusCode.BADREQUEST, "IP address change is not allowed"); + } + + // Derive the set of node connectors that are being removed + Set toRemove = target.getNodeConnectors(); + toRemove.removeAll(conf.getNodeConnectors()); + List nodeConnectorStrings = null; + if (!toRemove.isEmpty()) { + nodeConnectorStrings = new ArrayList(); + for (NodeConnector nc : toRemove) { + nodeConnectorStrings.add(nc.toString()); + } + status = this.removePortsFromSubnet(conf.getName(), nodeConnectorStrings); + if (!status.isSuccess()) { + return status; + } + } + + // Derive the set of node connectors that are being added + Set toAdd = conf.getNodeConnectors(); + toAdd.removeAll(target.getNodeConnectors()); + if (!toAdd.isEmpty()) { + List nodeConnectorStringRemoved = nodeConnectorStrings; + nodeConnectorStrings = new ArrayList(); + for (NodeConnector nc : toAdd) { + nodeConnectorStrings.add(nc.toString()); + } + status = this.addPortsToSubnet(conf.getName(), nodeConnectorStrings); + if (!status.isSuccess()) { + // If any port was removed, add it back as a best recovery effort + if (!toRemove.isEmpty()) { + this.addPortsToSubnet(conf.getName(), nodeConnectorStringRemoved); + } + return status; + } + } + + // Update Configuration + subnetsConfigList.put(conf.getName(), conf); + + return new Status(StatusCode.SUCCESS); + } + + @Override + public Status addPortsToSubnet(String name, List switchPorts) { + if (name == null) { + return new Status(StatusCode.BADREQUEST, "Null subnet name"); + } SubnetConfig confCurr = subnetsConfigList.get(name); if (confCurr == null) { return new Status(StatusCode.NOTFOUND, "Subnet does not exist"); } - if (!confCurr.isValidSwitchPort(switchPorts)) { - return new Status(StatusCode.BADREQUEST, "Invalid switchports"); + + if (switchPorts == null || switchPorts.isEmpty()) { + return new Status(StatusCode.BADREQUEST, "Null or empty port set"); } - Subnet subCurr = subnets.get(confCurr.getIPnum()); + Subnet subCurr = subnets.get(confCurr.getIPAddress()); if (subCurr == null) { - log.debug("Cluster conflict: Subnet entry {} is not present in the subnets cache.", confCurr.getIPnum()); + log.debug("Cluster conflict: Subnet entry {} is not present in the subnets cache.", confCurr.getIPAddress()); return new Status(StatusCode.NOTFOUND, "Subnet does not exist"); } // Update Database Subnet sub = subCurr.clone(); - Set sp = confCurr.getNodeConnectors(switchPorts); + Set sp = NodeConnector.fromString(switchPorts); sub.addNodeConnectors(sp); - boolean subnetsReplaced = subnets.replace(confCurr.getIPnum(), subCurr, sub); + boolean subnetsReplaced = subnets.replace(confCurr.getIPAddress(), subCurr, sub); if (!subnetsReplaced) { String msg = "Cluster conflict: Conflict while adding ports to the subnet " + name; return new Status(StatusCode.CONFLICT, msg); @@ -524,23 +609,35 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa } @Override - public Status removePortsFromSubnet(String name, String switchPorts) { + public Status removePortsFromSubnet(String name, List switchPorts) { + if (name == null) { + return new Status(StatusCode.BADREQUEST, "Null subnet name"); + } SubnetConfig confCurr = subnetsConfigList.get(name); if (confCurr == null) { return new Status(StatusCode.NOTFOUND, "Subnet does not exist"); } - Subnet subCurr = subnets.get(confCurr.getIPnum()); + if (switchPorts == null || switchPorts.isEmpty()) { + return new Status(StatusCode.BADREQUEST, "Null or empty port set"); + } + + Subnet subCurr = subnets.get(confCurr.getIPAddress()); if (subCurr == null) { - log.debug("Cluster conflict: Subnet entry {} is not present in the subnets cache.", confCurr.getIPnum()); + log.debug("Cluster conflict: Subnet entry {} is not present in the subnets cache.", confCurr.getIPAddress()); return new Status(StatusCode.NOTFOUND, "Subnet does not exist"); } + // Validation check + Status status = SubnetConfig.validatePorts(switchPorts); + if (!status.isSuccess()) { + return status; + } // Update Database Subnet sub = subCurr.clone(); - Set sp = confCurr.getNodeConnectors(switchPorts); + Set sp = NodeConnector.fromString(switchPorts); sub.deleteNodeConnectors(sp); - boolean subnetsReplace = subnets.replace(confCurr.getIPnum(), subCurr, sub); + boolean subnetsReplace = subnets.replace(confCurr.getIPAddress(), subCurr, sub); if (!subnetsReplace) { String msg = "Cluster conflict: Conflict while removing ports from the subnet " + name; return new Status(StatusCode.CONFLICT, msg); @@ -568,12 +665,14 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa @Override public Subnet getSubnetByNetworkAddress(InetAddress networkAddress) { - Subnet sub; - Set indices = subnets.keySet(); - for (InetAddress i : indices) { - sub = subnets.get(i); - if (sub.isSubnetOf(networkAddress)) { - return sub; + // if there are no subnets, return the default subnet + if (subnets.size() == 0) { + return DEFAULT_SUBNET; + } + + for(Map.Entry subnetEntry : subnets.entrySet()) { + if(subnetEntry.getValue().isSubnetOf(networkAddress)) { + return subnetEntry.getValue(); } } return null; @@ -587,51 +686,25 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa return ois.readObject(); } - @SuppressWarnings("unchecked") private void loadSubnetConfiguration() { - ObjectReader objReader = new ObjectReader(); - ConcurrentMap confList = (ConcurrentMap) objReader - .read(this, subnetFileName); - - if (confList == null) { - return; - } - - for (SubnetConfig conf : confList.values()) { - addSubnet(conf); + for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, SUBNETS_FILE_NAME)) { + addSubnet((SubnetConfig) conf); } } - @SuppressWarnings("unchecked") private void loadSpanConfiguration() { - ObjectReader objReader = new ObjectReader(); - ConcurrentMap confList = (ConcurrentMap) objReader - .read(this, spanFileName); - - if (confList == null) { - return; - } - - for (SpanConfig conf : confList.values()) { - addSpanConfig(conf); + for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, SPAN_FILE_NAME)) { + addSpanConfig((SpanConfig) conf); } } - @SuppressWarnings("unchecked") private void loadSwitchConfiguration() { - ObjectReader objReader = new ObjectReader(); - ConcurrentMap confList = (ConcurrentMap) objReader - .read(this, switchConfigFileName); - - if (confList == null) { - return; - } - - for (SwitchConfig conf : confList.values()) { - updateNodeConfig(conf); + for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, SWITCH_CONFIG_FILE_NAME)) { + updateNodeConfig((SwitchConfig) conf); } } + @SuppressWarnings("deprecation") @Override public void updateSwitchConfig(SwitchConfig cfgObject) { // update default container only @@ -673,7 +746,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa return; } - log.info("Set Node {}'s Mode to {}", nodeId, cfgObject.getMode()); + log.trace("Set Node {}'s Mode to {}", nodeId, cfgObject.getMode()); if (modeChange) { notifyModeChange(node, cfgObject.isProactive()); @@ -767,9 +840,14 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa String prop = entry.getKey(); if (!updateProperties.containsKey(prop)) { if (prop.equals(Description.propertyName)) { - if (!advertisedDesc.isEmpty()) { - Property desc = new Description(advertisedDesc); - propMap.put(Description.propertyName, desc); + if (advertisedDesc != null) { + if (!advertisedDesc.isEmpty()) { + Property desc = new Description(advertisedDesc); + propMap.put(Description.propertyName, desc); + } + } + else { + propMap.remove(prop); } continue; } else if (prop.equals(ForwardingMode.name)) { @@ -828,24 +906,36 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa } public Status saveSwitchConfigInternal() { - Status retS = null, retP = null; - ObjectWriter objWriter = new ObjectWriter(); - - retS = objWriter.write(new ConcurrentHashMap( - subnetsConfigList), subnetFileName); - retP = objWriter.write(new ConcurrentHashMap( - spanConfigList), spanFileName); - retS = objWriter.write(new ConcurrentHashMap( - nodeConfigList), switchConfigFileName); - if (retS.equals(retP)) { - if (retS.isSuccess()) { - return retS; - } else { - return new Status(StatusCode.INTERNALERROR, "Save failed"); - } + Status status; + short number = 0; + status = configurationService.persistConfiguration( + new ArrayList(subnetsConfigList.values()), SUBNETS_FILE_NAME); + if (status.isSuccess()) { + number++; + } else { + log.warn("Failed to save subnet gateway configurations: " + status.getDescription()); + } + status = configurationService.persistConfiguration(new ArrayList(spanConfigList.values()), + SPAN_FILE_NAME); + if (status.isSuccess()) { + number++; + } else { + log.warn("Failed to save span port configurations: " + status.getDescription()); + } + status = configurationService.persistConfiguration(new ArrayList(nodeConfigList.values()), + SWITCH_CONFIG_FILE_NAME); + if (status.isSuccess()) { + number++; } else { + log.warn("Failed to save node configurations: " + status.getDescription()); + } + if (number == 0) { + return new Status(StatusCode.INTERNALERROR, "Save failed"); + } + if (number < 3) { return new Status(StatusCode.INTERNALERROR, "Partial save failure"); } + return status; } @Override @@ -915,7 +1005,8 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa } } - boolean proactiveForwarding = false; + boolean forwardingModeChanged = false; + // copy node properties from config if (nodeConfigList != null) { String nodeId = node.toString(); @@ -925,7 +1016,19 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa propMap.putAll(nodeProperties); if (nodeProperties.get(ForwardingMode.name) != null) { ForwardingMode mode = (ForwardingMode) nodeProperties.get(ForwardingMode.name); - proactiveForwarding = mode.isProactive(); + forwardingModeChanged = mode.isProactive(); + } + } else if ((conf == null) && !(GlobalConstants.DEFAULT.toString().equals(containerName))) { + ISwitchManager defaultSwitchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, GlobalConstants.DEFAULT.toString(), this); + if (defaultSwitchManager != null) { + Property defaultContainerSwitchDesc = (Description) defaultSwitchManager.getNodeProp(node, Description.propertyName); + if (defaultContainerSwitchDesc != null) { + Map descPropMap = new HashMap(); + descPropMap.put(Description.propertyName, defaultContainerSwitchDesc); + conf = new SwitchConfig(nodeId, descPropMap); + updateNodeConfig(conf); + propMap.put(Description.propertyName, defaultContainerSwitchDesc); + } } } } @@ -934,28 +1037,35 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa Property defaultMode = new ForwardingMode(ForwardingMode.REACTIVE_FORWARDING); propMap.put(ForwardingMode.name, defaultMode); } - boolean result = false; - if (propMapCurr == null) { - if (nodeProps.putIfAbsent(node, propMap) == null) { - result = true; - } + + boolean propsAdded = false; + // Attempt initial add + if (nodeProps.putIfAbsent(node, propMap) == null) { + propsAdded = true; + + /* Notify listeners only for initial node addition + * to avoid expensive tasks triggered by redundant notifications + */ + notifyNode(node, UpdateType.ADDED, propMap); } else { - result = nodeProps.replace(node, propMapCurr, propMap); + + propsAdded = nodeProps.replace(node, propMapCurr, propMap); + + // check whether forwarding mode changed + if (propMapCurr.get(ForwardingMode.name) != null) { + ForwardingMode mode = (ForwardingMode) propMapCurr.get(ForwardingMode.name); + forwardingModeChanged ^= mode.isProactive(); + } } - if (!result) { - log.debug("Cluster conflict: Conflict while adding the node properties. Node: {} Properties: {}", - node.getID(), props); + if (!propsAdded) { + log.debug("Cluster conflict while adding node {}. Overwriting with latest props: {}", node.getID(), props); addNodeProps(node, propMap); } - // check if span ports are configed + // check if span ports are configured addSpanPorts(node); - - // notify node listeners - notifyNode(node, UpdateType.ADDED, propMap); - // notify proactive mode forwarding - if (proactiveForwarding) { + if (forwardingModeChanged) { notifyModeChange(node, true); } } @@ -965,7 +1075,12 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa if (nodeProps == null) { return; } - nodeProps.remove(node); + + if (nodeProps.remove(node) == null) { + log.debug("Received redundant node REMOVED udate for {}. Skipping..", node); + return; + } + nodeConnectorNames.remove(node); Set removeNodeConnectorSet = new HashSet(); for (Map.Entry> entry : nodeConnectorProps.entrySet()) { @@ -987,8 +1102,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa private void updateNode(Node node, Set props) { log.trace("{} updated, props: {}", node, props); - if (nodeProps == null || !nodeProps.containsKey(node) || - props == null || props.isEmpty()) { + if (nodeProps == null || props == null) { return; } @@ -1061,6 +1175,13 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa switch (type) { case ADDED: + // Skip redundant ADDED update (e.g. cluster switch-over) + if (nodeConnectorProps.containsKey(nodeConnector)) { + log.debug("Redundant nodeconnector ADDED for {}, props {} for container {}", + nodeConnector, props, containerName); + update = false; + } + if (props != null) { for (Property prop : props) { addNodeConnectorProp(nodeConnector, prop); @@ -1070,6 +1191,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa addNodeConnectorProp(nodeConnector, null); } + addSpanPort(nodeConnector); break; case CHANGED: @@ -1103,8 +1225,46 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa @Override public Set getNodes() { - return (nodeProps != null) ? new HashSet(nodeProps.keySet()) - : new HashSet(); + return (nodeProps != null) ? new HashSet(nodeProps.keySet()) : new HashSet(); + } + + @Override + public Map getControllerProperties() { + return new HashMap(this.controllerProps); + } + + @Override + public Property getControllerProperty(String propertyName) { + if (propertyName != null) { + HashMap propertyMap = new HashMap(this.controllerProps); + return propertyMap.get(propertyName); + } + return null; + } + + @Override + public Status setControllerProperty(Property property) { + if (property != null) { + this.controllerProps.put(property.getName(), property); + return new Status(StatusCode.SUCCESS); + } + return new Status(StatusCode.BADREQUEST, "Invalid property provided when setting property"); + } + + @Override + public Status removeControllerProperty(String propertyName) { + if (propertyName != null) { + if (this.controllerProps.containsKey(propertyName)) { + this.controllerProps.remove(propertyName); + if (!this.controllerProps.containsKey(propertyName)) { + return new Status(StatusCode.SUCCESS); + } + } + String msg = "Unable to remove property " + propertyName + " from Controller"; + return new Status(StatusCode.BADREQUEST, msg); + } + String msg = "Invalid property provided when removing property from Controller"; + return new Status(StatusCode.BADREQUEST, msg); } /* @@ -1151,10 +1311,6 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa if (nodeProps.replace(node, propMapCurr, propMap)) { return; } - if (!propMapCurr.get(prop.getName()).equals(nodeProps.get(node).get(prop.getName()))) { - log.debug("Cluster conflict: Unable to add property {} to node {}.", prop.getName(), node.getID()); - return; - } } log.warn("Cluster conflict: Unable to add property {} to node {}.", prop.getName(), node.getID()); } @@ -1172,12 +1328,6 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa if (nodeProps.replace(node, propMapCurr, propMap)) { return new Status(StatusCode.SUCCESS); } - if (!propMapCurr.get(propName).equals(nodeProps.get(node).get(propName))) { - String msg = "Cluster conflict: Unable to remove property " + propName + " for node " - + node.getID(); - return new Status(StatusCode.CONFLICT, msg); - } - } else { return new Status(StatusCode.SUCCESS); } @@ -1268,52 +1418,12 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa return (propMap != null) ? propMap.get(propName) : null; } - private byte[] getHardwareMAC() { - Enumeration nis; - byte[] macAddress = null; - - try { - nis = NetworkInterface.getNetworkInterfaces(); - } catch (SocketException e) { - log.error("Failed to acquire controller MAC: ", e); - return macAddress; - } - - while (nis.hasMoreElements()) { - NetworkInterface ni = nis.nextElement(); - try { - macAddress = ni.getHardwareAddress(); - } catch (SocketException e) { - log.error("Failed to acquire controller MAC: ", e); - } - if (macAddress != null) { - break; - } - } - if (macAddress == null) { - log.warn("Failed to acquire controller MAC: No physical interface found"); - // This happens when running controller on windows VM, for example - // Try parsing the OS command output - } - return macAddress; - } - @Override public byte[] getControllerMAC() { MacAddress macProperty = (MacAddress)controllerProps.get(MacAddress.name); return (macProperty == null) ? null : macProperty.getMacAddress(); } - @Override - public boolean isHostRefreshEnabled() { - return hostRefresh; - } - - @Override - public int getHostRetryCount() { - return hostRetryCount; - } - @Override public NodeConnector getNodeConnector(Node node, String nodeConnectorName) { if (nodeConnectorNames == null) { @@ -1382,7 +1492,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa try { map.put(s, new NodeConnector(entry.getValue())); } catch (ConstructionException e) { - e.printStackTrace(); + log.error("An error occured",e); } } } @@ -1444,7 +1554,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa try { map.put(s, new NodeConnector(entry.getValue())); } catch (ConstructionException e) { - e.printStackTrace(); + log.error("An error occured",e); } } map.remove(name.getValue()); @@ -1481,7 +1591,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa try { map.put(s, new NodeConnector(entry.getValue())); } catch (ConstructionException e) { - e.printStackTrace(); + log.error("An error occured",e); } } map.remove(name.getValue()); @@ -1519,7 +1629,6 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa isDefaultContainer = containerName.equals(GlobalConstants.DEFAULT .toString()); - startUp(); } /** @@ -1538,6 +1647,15 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa * */ void start() { + startUp(); + + /* + * Read startup and build database if we are the coordinator + */ + loadSubnetConfiguration(); + loadSpanConfiguration(); + loadSwitchConfiguration(); + // OSGI console registerWithOSGIConsole(); } @@ -1559,6 +1677,16 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa void stop() { } + 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; + } + public void setInventoryService(IInventoryService service) { log.trace("Got inventory service set request {}", service); this.inventoryService = service; @@ -1648,6 +1776,16 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa } } + public void setControllerProperties(IControllerProperties controllerProperties) { + log.trace("Got controller properties set request {}", controllerProperties); + this.controllerProperties = controllerProperties; + } + + public void unsetControllerProperties(IControllerProperties controllerProperties) { + log.trace("Got controller properties UNset request"); + this.controllerProperties = null; + } + private void getInventories() { if (inventoryService == null) { log.trace("inventory service not avaiable"); @@ -1762,15 +1900,18 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa && (state != null) && (state.getValue() == State.EDGE_UP)); } + @Override + public boolean doesNodeConnectorExist(NodeConnector nc) { + return (nc != null && nodeConnectorProps != null + && nodeConnectorProps.containsKey(nc)); + } + @Override public String getHelp() { StringBuffer help = new StringBuffer(); help.append("---Switch Manager---\n"); help.append("\t pencs - Print enabled node connectors for a given node\n"); help.append("\t pdm - Print switch ports in device map\n"); - help.append("\t snt - Set node tier number\n"); - help.append("\t hostRefresh - Enable/Disable/Query host refresh\n"); - help.append("\t hostRetry - Set host retry count\n"); return help.toString(); } @@ -1816,9 +1957,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa Switch sw = getSwitchByNode(node); ci.println(" NodeConnector Name"); - if (sw == null) { - return; - } + Set nodeConnectorSet = sw.getNodeConnectors(); String nodeConnectorName; if (nodeConnectorSet != null && nodeConnectorSet.size() > 0) { @@ -1855,66 +1994,6 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa } } - public void _snt(CommandInterpreter ci) { - String st = ci.nextArgument(); - if (st == null) { - ci.println("Please enter node id"); - return; - } - - Node node = Node.fromString(st); - if (node == null) { - ci.println("Please enter node id"); - return; - } - - st = ci.nextArgument(); - if (st == null) { - ci.println("Please enter tier number"); - return; - } - Integer tid = Integer.decode(st); - Tier tier = new Tier(tid); - setNodeProp(node, tier); - } - - public void _hostRefresh(CommandInterpreter ci) { - String mode = ci.nextArgument(); - if (mode == null) { - ci.println("expecting on/off/?"); - return; - } - if (mode.toLowerCase().equals("on")) { - hostRefresh = true; - } else if (mode.toLowerCase().equals("off")) { - hostRefresh = false; - } else if (mode.equals("?")) { - if (hostRefresh) { - ci.println("host refresh is ON"); - } else { - ci.println("host refresh is OFF"); - } - } else { - ci.println("expecting on/off/?"); - } - return; - } - - public void _hostRetry(CommandInterpreter ci) { - String retry = ci.nextArgument(); - if (retry == null) { - ci.println("Please enter a valid number. Current retry count is " - + hostRetryCount); - return; - } - try { - hostRetryCount = Integer.parseInt(retry); - } catch (Exception e) { - ci.println("Please enter a valid number"); - } - return; - } - @Override public byte[] getNodeMAC(Node node) { MacAddress mac = (MacAddress) this.getNodeProp(node, @@ -1961,9 +2040,9 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa // only add if span is configured on this nodeConnector for (SpanConfig conf : getSpanConfigList(nodeConnector.getNode())) { if (conf.getPortArrayList().contains(nodeConnector)) { - List ncLists = new ArrayList(); - ncLists.add(nodeConnector); - addSpanPorts(nodeConnector.getNode(), ncLists); + List ncList = new ArrayList(); + ncList.add(nodeConnector); + addSpanPorts(nodeConnector.getNode(), ncList); return; } } @@ -2014,8 +2093,9 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa } /** - * Creates a Name/Tier/Bandwidth Property object based on given property - * name and value. Other property types are not supported yet. + * Creates a Name/Tier/Bandwidth/MacAddress(controller property) Property + * object based on given property name and value. Other property types are + * not supported yet. * * @param propName * Name of the Property @@ -2046,7 +2126,10 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa } else if (propName.equalsIgnoreCase(ForwardingMode.name)) { int mode = Integer.parseInt(propValue); return new ForwardingMode(mode); - } else { + } else if (propName.equalsIgnoreCase(MacAddress.name)){ + return new MacAddress(propValue); + } + else { log.debug("Not able to create {} property", propName); } } catch (Exception e) { @@ -2056,6 +2139,8 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa return null; } + + @SuppressWarnings("deprecation") @Override public String getNodeDescription(Node node) { // Check first if user configured a name @@ -2073,4 +2158,23 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa return (desc == null /* || desc.getValue().equalsIgnoreCase("none") */) ? "" : desc.getValue(); } + + @Override + public Set getConfiguredNotConnectedSwitches() { + Set configuredNotConnectedSwitches = new HashSet(); + if (this.inventoryService == null) { + log.trace("inventory service not available"); + return configuredNotConnectedSwitches; + } + + Set configuredNotConnectedNodes = this.inventoryService.getConfiguredNotConnectedNodes(); + if (configuredNotConnectedNodes != null) { + for (Node node : configuredNotConnectedNodes) { + Switch sw = getSwitchByNode(node); + configuredNotConnectedSwitches.add(sw); + } + } + return configuredNotConnectedSwitches; + } + }