2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.switchmanager.internal;
11 import java.io.FileNotFoundException;
12 import java.io.IOException;
13 import java.io.ObjectInputStream;
14 import java.net.InetAddress;
15 import java.net.NetworkInterface;
16 import java.net.SocketException;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Dictionary;
20 import java.util.EnumSet;
21 import java.util.Enumeration;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.List;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.ConcurrentMap;
29 import java.util.concurrent.CopyOnWriteArrayList;
31 import org.apache.felix.dm.Component;
32 import org.eclipse.osgi.framework.console.CommandInterpreter;
33 import org.eclipse.osgi.framework.console.CommandProvider;
34 import org.opendaylight.controller.clustering.services.CacheConfigException;
35 import org.opendaylight.controller.clustering.services.CacheExistException;
36 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
37 import org.opendaylight.controller.clustering.services.IClusterServices;
38 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
39 import org.opendaylight.controller.sal.core.Bandwidth;
40 import org.opendaylight.controller.sal.core.Config;
41 import org.opendaylight.controller.sal.core.ConstructionException;
42 import org.opendaylight.controller.sal.core.Description;
43 import org.opendaylight.controller.sal.core.ForwardingMode;
44 import org.opendaylight.controller.sal.core.MacAddress;
45 import org.opendaylight.controller.sal.core.Name;
46 import org.opendaylight.controller.sal.core.Node;
47 import org.opendaylight.controller.sal.core.NodeConnector;
48 import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
49 import org.opendaylight.controller.sal.core.Property;
50 import org.opendaylight.controller.sal.core.State;
51 import org.opendaylight.controller.sal.core.Tier;
52 import org.opendaylight.controller.sal.core.UpdateType;
53 import org.opendaylight.controller.sal.inventory.IInventoryService;
54 import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
55 import org.opendaylight.controller.sal.reader.NodeDescription;
56 import org.opendaylight.controller.sal.utils.GlobalConstants;
57 import org.opendaylight.controller.sal.utils.HexEncode;
58 import org.opendaylight.controller.sal.utils.IObjectReader;
59 import org.opendaylight.controller.sal.utils.ObjectReader;
60 import org.opendaylight.controller.sal.utils.ObjectWriter;
61 import org.opendaylight.controller.sal.utils.Status;
62 import org.opendaylight.controller.sal.utils.StatusCode;
63 import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
64 import org.opendaylight.controller.switchmanager.IInventoryListener;
65 import org.opendaylight.controller.switchmanager.ISpanAware;
66 import org.opendaylight.controller.switchmanager.ISwitchManager;
67 import org.opendaylight.controller.switchmanager.ISwitchManagerAware;
68 import org.opendaylight.controller.switchmanager.SpanConfig;
69 import org.opendaylight.controller.switchmanager.Subnet;
70 import org.opendaylight.controller.switchmanager.SubnetConfig;
71 import org.opendaylight.controller.switchmanager.Switch;
72 import org.opendaylight.controller.switchmanager.SwitchConfig;
73 import org.osgi.framework.BundleContext;
74 import org.osgi.framework.FrameworkUtil;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
79 * The class describes SwitchManager which is the central repository of all the
80 * inventory data including nodes, node connectors, properties attached, Layer3
81 * configurations, Span configurations, node configurations, network device
82 * representations viewed by Controller Web applications. One SwitchManager
83 * instance per container of the network. All the node/nodeConnector properties
84 * are maintained in the default container only.
86 public class SwitchManager implements ISwitchManager, IConfigurationContainerAware,
87 IObjectReader, IListenInventoryUpdates, CommandProvider {
88 private static Logger log = LoggerFactory.getLogger(SwitchManager.class);
89 private static String ROOT = GlobalConstants.STARTUPHOME.toString();
90 private String subnetFileName, spanFileName, switchConfigFileName;
91 private final List<NodeConnector> spanNodeConnectors = new CopyOnWriteArrayList<NodeConnector>();
92 // Collection of Subnets keyed by the InetAddress
93 private ConcurrentMap<InetAddress, Subnet> subnets;
94 private ConcurrentMap<String, SubnetConfig> subnetsConfigList;
95 private ConcurrentMap<SpanConfig, SpanConfig> spanConfigList;
96 // manually configured parameters for the node such as name, tier, mode
97 private ConcurrentMap<String, SwitchConfig> nodeConfigList;
98 private ConcurrentMap<Node, Map<String, Property>> nodeProps;
99 private ConcurrentMap<NodeConnector, Map<String, Property>> nodeConnectorProps;
100 private ConcurrentMap<Node, Map<String, NodeConnector>> nodeConnectorNames;
101 private ConcurrentMap<String, Property> controllerProps;
102 private IInventoryService inventoryService;
103 private IStatisticsManager statisticsManager;
104 private final Set<ISwitchManagerAware> switchManagerAware = Collections
105 .synchronizedSet(new HashSet<ISwitchManagerAware>());
106 private final Set<IInventoryListener> inventoryListeners = Collections
107 .synchronizedSet(new HashSet<IInventoryListener>());
108 private final Set<ISpanAware> spanAware = Collections.synchronizedSet(new HashSet<ISpanAware>());
109 private IClusterContainerServices clusterContainerService = null;
110 private String containerName = null;
111 private boolean isDefaultContainer = true;
112 private static final int REPLACE_RETRY = 1;
114 /* Information about the default subnet. If there have been no configured subnets, i.e.,
115 * subnets.size() == 0 or subnetsConfigList.size() == 0, then this subnet will be the
116 * only subnet returned. As soon as a user-configured subnet is created this one will
119 protected static SubnetConfig DEFAULT_SUBNETCONFIG;
120 protected static Subnet DEFAULT_SUBNET;
121 protected static String DEFAULT_SUBNET_NAME = "default (cannot be modifed)";
123 DEFAULT_SUBNETCONFIG = new SubnetConfig(DEFAULT_SUBNET_NAME, "0.0.0.0/0", new ArrayList<String>());
124 DEFAULT_SUBNET = new Subnet(DEFAULT_SUBNETCONFIG);
127 public void notifySubnetChange(Subnet sub, boolean add) {
128 synchronized (switchManagerAware) {
129 for (Object subAware : switchManagerAware) {
131 ((ISwitchManagerAware) subAware).subnetNotify(sub, add);
132 } catch (Exception e) {
133 log.error("Failed to notify Subnet change {}",
140 public void notifySpanPortChange(Node node, List<NodeConnector> ports, boolean add) {
141 synchronized (spanAware) {
142 for (Object sa : spanAware) {
144 ((ISpanAware) sa).spanUpdate(node, ports, add);
145 } catch (Exception e) {
146 log.error("Failed to notify Span Interface change {}",
153 private void notifyModeChange(Node node, boolean proactive) {
154 synchronized (switchManagerAware) {
155 for (ISwitchManagerAware service : switchManagerAware) {
157 service.modeChangeNotify(node, proactive);
158 } catch (Exception e) {
159 log.error("Failed to notify Subnet change {}",
166 public void startUp() {
167 String container = this.getContainerName();
168 // Initialize configuration file names
169 subnetFileName = ROOT + "subnets_" + container + ".conf";
170 spanFileName = ROOT + "spanPorts_" + container + ".conf";
171 switchConfigFileName = ROOT + "switchConfig_" + container + ".conf";
173 // Instantiate cluster synced variables
178 * Read startup and build database if we have not already gotten the
179 * configurations synced from another node
181 if (subnetsConfigList.isEmpty()) {
182 loadSubnetConfiguration();
184 if (spanConfigList.isEmpty()) {
185 loadSpanConfiguration();
187 if (nodeConfigList.isEmpty()) {
188 loadSwitchConfiguration();
191 // Add controller MAC, if first node in the cluster
192 if (!controllerProps.containsKey(MacAddress.name)) {
193 byte controllerMac[] = getHardwareMAC();
194 if (controllerMac != null) {
195 Property existing = controllerProps.putIfAbsent(MacAddress.name, new MacAddress(controllerMac));
196 if (existing == null && log.isTraceEnabled()) {
197 log.trace("Container {}: Setting controller MAC address in the cluster: {}", container,
198 HexEncode.bytesToHexStringFormat(controllerMac));
204 public void shutDown() {
207 private void allocateCaches() {
208 if (this.clusterContainerService == null) {
209 this.nonClusterObjectCreate();
210 log.warn("un-initialized clusterContainerService, can't create cache");
215 clusterContainerService.createCache(
216 "switchmanager.subnetsConfigList",
217 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
218 clusterContainerService.createCache("switchmanager.spanConfigList",
219 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
220 clusterContainerService.createCache("switchmanager.nodeConfigList",
221 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
222 clusterContainerService.createCache("switchmanager.subnets",
223 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
224 clusterContainerService.createCache("switchmanager.nodeProps",
225 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
226 clusterContainerService.createCache(
227 "switchmanager.nodeConnectorProps",
228 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
229 clusterContainerService.createCache(
230 "switchmanager.nodeConnectorNames",
231 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
232 clusterContainerService.createCache(
233 "switchmanager.controllerProps",
234 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
235 } catch (CacheConfigException cce) {
236 log.error("\nCache configuration invalid - check cache mode");
237 } catch (CacheExistException ce) {
238 log.error("\nCache already exits - destroy and recreate if needed");
242 @SuppressWarnings({ "unchecked" })
243 private void retrieveCaches() {
244 if (this.clusterContainerService == null) {
245 log.info("un-initialized clusterContainerService, can't create cache");
249 subnetsConfigList = (ConcurrentMap<String, SubnetConfig>) clusterContainerService
250 .getCache("switchmanager.subnetsConfigList");
251 if (subnetsConfigList == null) {
252 log.error("\nFailed to get cache for subnetsConfigList");
255 spanConfigList = (ConcurrentMap<SpanConfig, SpanConfig>) clusterContainerService
256 .getCache("switchmanager.spanConfigList");
257 if (spanConfigList == null) {
258 log.error("\nFailed to get cache for spanConfigList");
261 nodeConfigList = (ConcurrentMap<String, SwitchConfig>) clusterContainerService
262 .getCache("switchmanager.nodeConfigList");
263 if (nodeConfigList == null) {
264 log.error("\nFailed to get cache for nodeConfigList");
267 subnets = (ConcurrentMap<InetAddress, Subnet>) clusterContainerService
268 .getCache("switchmanager.subnets");
269 if (subnets == null) {
270 log.error("\nFailed to get cache for subnets");
273 nodeProps = (ConcurrentMap<Node, Map<String, Property>>) clusterContainerService
274 .getCache("switchmanager.nodeProps");
275 if (nodeProps == null) {
276 log.error("\nFailed to get cache for nodeProps");
279 nodeConnectorProps = (ConcurrentMap<NodeConnector, Map<String, Property>>) clusterContainerService
280 .getCache("switchmanager.nodeConnectorProps");
281 if (nodeConnectorProps == null) {
282 log.error("\nFailed to get cache for nodeConnectorProps");
285 nodeConnectorNames = (ConcurrentMap<Node, Map<String, NodeConnector>>) clusterContainerService
286 .getCache("switchmanager.nodeConnectorNames");
287 if (nodeConnectorNames == null) {
288 log.error("\nFailed to get cache for nodeConnectorNames");
291 controllerProps = (ConcurrentMap<String, Property>) clusterContainerService
292 .getCache("switchmanager.controllerProps");
293 if (controllerProps == null) {
294 log.error("\nFailed to get cache for controllerProps");
298 private void nonClusterObjectCreate() {
299 subnetsConfigList = new ConcurrentHashMap<String, SubnetConfig>();
300 spanConfigList = new ConcurrentHashMap<SpanConfig, SpanConfig>();
301 nodeConfigList = new ConcurrentHashMap<String, SwitchConfig>();
302 subnets = new ConcurrentHashMap<InetAddress, Subnet>();
303 nodeProps = new ConcurrentHashMap<Node, Map<String, Property>>();
304 nodeConnectorProps = new ConcurrentHashMap<NodeConnector, Map<String, Property>>();
305 nodeConnectorNames = new ConcurrentHashMap<Node, Map<String, NodeConnector>>();
306 controllerProps = new ConcurrentHashMap<String, Property>();
310 public List<SubnetConfig> getSubnetsConfigList() {
311 // if there are no subnets, return the default subnet
312 if(subnetsConfigList.size() == 0){
313 return Collections.singletonList(DEFAULT_SUBNETCONFIG);
315 return new ArrayList<SubnetConfig>(subnetsConfigList.values());
320 public SubnetConfig getSubnetConfig(String subnet) {
321 // if there are no subnets, return the default subnet
322 if(subnetsConfigList.size() == 0 && subnet == DEFAULT_SUBNET_NAME){
323 return DEFAULT_SUBNETCONFIG;
325 return subnetsConfigList.get(subnet);
329 private List<SpanConfig> getSpanConfigList(Node node) {
330 List<SpanConfig> confList = new ArrayList<SpanConfig>();
331 String nodeId = node.toString();
332 for (SpanConfig conf : spanConfigList.values()) {
333 if (conf.matchNode(nodeId)) {
340 public List<SwitchConfig> getNodeConfigList() {
341 return new ArrayList<SwitchConfig>(nodeConfigList.values());
345 public SwitchConfig getSwitchConfig(String switchId) {
346 return nodeConfigList.get(switchId);
349 public Switch getSwitchByNode(Node node) {
350 Switch sw = new Switch(node);
352 MacAddress mac = (MacAddress) this.getNodeProp(node,
355 sw.setDataLayerAddress(mac.getMacAddress());
357 Set<NodeConnector> ncSet = getPhysicalNodeConnectors(node);
358 sw.setNodeConnectors(ncSet);
360 List<NodeConnector> ncList = new ArrayList<NodeConnector>();
361 for (NodeConnector nodeConnector : ncSet) {
362 if (spanNodeConnectors.contains(nodeConnector)) {
363 ncList.add(nodeConnector);
366 sw.addSpanPorts(ncList);
372 public List<Switch> getNetworkDevices() {
373 Set<Node> nodeSet = getNodes();
374 List<Switch> swList = new ArrayList<Switch>();
375 if (nodeSet != null) {
376 for (Node node : nodeSet) {
377 swList.add(getSwitchByNode(node));
384 private Status updateConfig(SubnetConfig conf, boolean add) {
386 if(subnetsConfigList.putIfAbsent(conf.getName(), conf) != null) {
387 String msg = "Cluster conflict: Subnet with name " + conf.getName() + "already exists.";
388 return new Status(StatusCode.CONFLICT, msg);
391 subnetsConfigList.remove(conf.getName());
393 return new Status(StatusCode.SUCCESS);
396 private Status updateDatabase(SubnetConfig conf, boolean add) {
398 Subnet subnetCurr = subnets.get(conf.getIPAddress());
400 if (subnetCurr == null) {
401 subnet = new Subnet(conf);
403 subnet = subnetCurr.clone();
405 // In case of API3 call we may receive the ports along with the
407 if (!conf.isGlobal()) {
408 subnet.addNodeConnectors(conf.getNodeConnectors());
410 boolean putNewSubnet = false;
411 if(subnetCurr == null) {
412 if(subnets.putIfAbsent(conf.getIPAddress(), subnet) == null) {
416 putNewSubnet = subnets.replace(conf.getIPAddress(), subnetCurr, subnet);
419 String msg = "Cluster conflict: Conflict while adding the subnet " + conf.getIPAddress();
420 return new Status(StatusCode.CONFLICT, msg);
423 // Subnet removal case
425 subnets.remove(conf.getIPAddress());
427 return new Status(StatusCode.SUCCESS);
430 private Status semanticCheck(SubnetConfig conf) {
431 Subnet newSubnet = new Subnet(conf);
432 Set<InetAddress> IPs = subnets.keySet();
434 return new Status(StatusCode.SUCCESS);
436 for (InetAddress i : IPs) {
437 Subnet existingSubnet = subnets.get(i);
438 if ((existingSubnet != null) && !existingSubnet.isMutualExclusive(newSubnet)) {
439 return new Status(StatusCode.CONFLICT, "This subnet conflicts with an existing one.");
442 return new Status(StatusCode.SUCCESS);
445 private Status addRemoveSubnet(SubnetConfig conf, boolean isAdding) {
446 // Valid configuration check
447 Status status = conf.validate();
448 if (!status.isSuccess()) {
449 log.warn(status.getDescription());
455 if (subnetsConfigList.containsKey(conf.getName())) {
456 return new Status(StatusCode.CONFLICT,
457 "Subnet with the specified name already exists.");
460 status = semanticCheck(conf);
461 if (!status.isSuccess()) {
467 status = updateDatabase(conf, isAdding);
469 if (status.isSuccess()) {
470 // Update Configuration
471 status = updateConfig(conf, isAdding);
472 if(!status.isSuccess()) {
473 updateDatabase(conf, (!isAdding));
481 * Adds Subnet configured in GUI or API3
484 public Status addSubnet(SubnetConfig conf) {
485 return this.addRemoveSubnet(conf, true);
489 public Status removeSubnet(SubnetConfig conf) {
490 return this.addRemoveSubnet(conf, false);
494 public Status removeSubnet(String name) {
495 SubnetConfig conf = subnetsConfigList.get(name);
497 return new Status(StatusCode.SUCCESS, "Subnet not present");
499 return this.addRemoveSubnet(conf, false);
503 public Status modifySubnet(SubnetConfig conf) {
506 return new Status(StatusCode.BADREQUEST, "Invalid Subnet configuration: null");
509 // Valid configuration check
510 Status status = conf.validate();
511 if (!status.isSuccess()) {
512 log.warn(status.getDescription());
516 // If a subnet configuration with this name does not exist, consider this is a creation
517 SubnetConfig target = subnetsConfigList.get(conf.getName());
518 if (target == null) {
519 return this.addSubnet(conf);
523 if (target.equals(conf)) {
524 return new Status(StatusCode.SUCCESS);
527 // Check not allowed modifications
528 if (!target.getSubnet().equals(conf.getSubnet())) {
529 return new Status(StatusCode.BADREQUEST, "IP address change is not allowed");
532 // Derive the set of node connectors that are being removed
533 Set<NodeConnector> toRemove = target.getNodeConnectors();
534 toRemove.removeAll(conf.getNodeConnectors());
535 List<String> nodeConnectorStrings = null;
536 if (!toRemove.isEmpty()) {
537 nodeConnectorStrings = new ArrayList<String>();
538 for (NodeConnector nc : toRemove) {
539 nodeConnectorStrings.add(nc.toString());
541 status = this.removePortsFromSubnet(conf.getName(), nodeConnectorStrings);
542 if (!status.isSuccess()) {
547 // Derive the set of node connectors that are being added
548 Set<NodeConnector> toAdd = conf.getNodeConnectors();
549 toAdd.removeAll(target.getNodeConnectors());
550 if (!toAdd.isEmpty()) {
551 List<String> nodeConnectorStringRemoved = nodeConnectorStrings;
552 nodeConnectorStrings = new ArrayList<String>();
553 for (NodeConnector nc : toAdd) {
554 nodeConnectorStrings.add(nc.toString());
556 status = this.addPortsToSubnet(conf.getName(), nodeConnectorStrings);
557 if (!status.isSuccess()) {
558 // If any port was removed, add it back as a best recovery effort
559 if (!toRemove.isEmpty()) {
560 this.addPortsToSubnet(conf.getName(), nodeConnectorStringRemoved);
566 // Update Configuration
567 subnetsConfigList.put(conf.getName(), conf);
569 return new Status(StatusCode.SUCCESS);
573 public Status addPortsToSubnet(String name, List<String> switchPorts) {
575 return new Status(StatusCode.BADREQUEST, "Null subnet name");
577 SubnetConfig confCurr = subnetsConfigList.get(name);
578 if (confCurr == null) {
579 return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
582 if (switchPorts == null || switchPorts.isEmpty()) {
583 return new Status(StatusCode.BADREQUEST, "Null or empty port set");
586 Subnet subCurr = subnets.get(confCurr.getIPAddress());
587 if (subCurr == null) {
588 log.debug("Cluster conflict: Subnet entry {} is not present in the subnets cache.", confCurr.getIPAddress());
589 return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
593 Subnet sub = subCurr.clone();
594 Set<NodeConnector> sp = NodeConnector.fromString(switchPorts);
595 sub.addNodeConnectors(sp);
596 boolean subnetsReplaced = subnets.replace(confCurr.getIPAddress(), subCurr, sub);
597 if (!subnetsReplaced) {
598 String msg = "Cluster conflict: Conflict while adding ports to the subnet " + name;
599 return new Status(StatusCode.CONFLICT, msg);
602 // Update Configuration
603 SubnetConfig conf = confCurr.clone();
604 conf.addNodeConnectors(switchPorts);
605 boolean configReplaced = subnetsConfigList.replace(name, confCurr, conf);
606 if (!configReplaced) {
607 // TODO: recovery using Transactionality
608 String msg = "Cluster conflict: Conflict while adding ports to the subnet " + name;
609 return new Status(StatusCode.CONFLICT, msg);
612 return new Status(StatusCode.SUCCESS);
616 public Status removePortsFromSubnet(String name, List<String> switchPorts) {
618 return new Status(StatusCode.BADREQUEST, "Null subnet name");
620 SubnetConfig confCurr = subnetsConfigList.get(name);
621 if (confCurr == null) {
622 return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
625 if (switchPorts == null || switchPorts.isEmpty()) {
626 return new Status(StatusCode.BADREQUEST, "Null or empty port set");
629 Subnet subCurr = subnets.get(confCurr.getIPAddress());
630 if (subCurr == null) {
631 log.debug("Cluster conflict: Subnet entry {} is not present in the subnets cache.", confCurr.getIPAddress());
632 return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
636 Status status = SubnetConfig.validatePorts(switchPorts);
637 if (!status.isSuccess()) {
641 Subnet sub = subCurr.clone();
642 Set<NodeConnector> sp = NodeConnector.fromString(switchPorts);
643 sub.deleteNodeConnectors(sp);
644 boolean subnetsReplace = subnets.replace(confCurr.getIPAddress(), subCurr, sub);
645 if (!subnetsReplace) {
646 String msg = "Cluster conflict: Conflict while removing ports from the subnet " + name;
647 return new Status(StatusCode.CONFLICT, msg);
650 // Update Configuration
651 SubnetConfig conf = confCurr.clone();
652 conf.removeNodeConnectors(switchPorts);
653 boolean result = subnetsConfigList.replace(name, confCurr, conf);
655 // TODO: recovery using Transactionality
656 String msg = "Cluster conflict: Conflict while removing ports from " + conf;
657 return new Status(StatusCode.CONFLICT, msg);
660 return new Status(StatusCode.SUCCESS);
663 public String getContainerName() {
664 if (containerName == null) {
665 return GlobalConstants.DEFAULT.toString();
667 return containerName;
671 public Subnet getSubnetByNetworkAddress(InetAddress networkAddress) {
672 // if there are no subnets, return the default subnet
673 if (subnets.size() == 0) {
674 return DEFAULT_SUBNET;
678 Set<InetAddress> indices = subnets.keySet();
679 for (InetAddress i : indices) {
680 sub = subnets.get(i);
681 if (sub.isSubnetOf(networkAddress)) {
689 public Object readObject(ObjectInputStream ois)
690 throws FileNotFoundException, IOException, ClassNotFoundException {
691 // Perform the class deserialization locally, from inside the package
692 // where the class is defined
693 return ois.readObject();
696 @SuppressWarnings("unchecked")
697 private void loadSubnetConfiguration() {
698 ObjectReader objReader = new ObjectReader();
699 ConcurrentMap<String, SubnetConfig> confList = (ConcurrentMap<String, SubnetConfig>) objReader
700 .read(this, subnetFileName);
702 if (confList == null) {
706 for (SubnetConfig conf : confList.values()) {
711 @SuppressWarnings("unchecked")
712 private void loadSpanConfiguration() {
713 ObjectReader objReader = new ObjectReader();
714 ConcurrentMap<Integer, SpanConfig> confList = (ConcurrentMap<Integer, SpanConfig>) objReader
715 .read(this, spanFileName);
717 if (confList == null) {
721 for (SpanConfig conf : confList.values()) {
726 @SuppressWarnings("unchecked")
727 private void loadSwitchConfiguration() {
728 ObjectReader objReader = new ObjectReader();
729 ConcurrentMap<String, SwitchConfig> confList = (ConcurrentMap<String, SwitchConfig>) objReader
730 .read(this, switchConfigFileName);
732 if (confList == null) {
736 for (SwitchConfig conf : confList.values()) {
737 updateNodeConfig(conf);
741 @SuppressWarnings("deprecation")
743 public void updateSwitchConfig(SwitchConfig cfgObject) {
744 // update default container only
745 if (!isDefaultContainer) {
749 SwitchConfig sc = nodeConfigList.get(cfgObject.getNodeId());
751 if (nodeConfigList.putIfAbsent(cfgObject.getNodeId(), cfgObject) != null) {
755 if (!nodeConfigList.replace(cfgObject.getNodeId(), sc, cfgObject)) {
760 boolean modeChange = false;
762 if ((sc == null) || !cfgObject.getMode().equals(sc.getMode())) {
766 String nodeId = cfgObject.getNodeId();
767 Node node = Node.fromString(nodeId);
768 Map<String, Property> propMapCurr = nodeProps.get(node);
769 if (propMapCurr == null) {
772 Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
773 Property desc = new Description(cfgObject.getNodeDescription());
774 propMap.put(desc.getName(), desc);
775 Property tier = new Tier(Integer.parseInt(cfgObject.getTier()));
776 propMap.put(tier.getName(), tier);
778 if (!nodeProps.replace(node, propMapCurr, propMap)) {
779 // TODO rollback using Transactionality
783 log.info("Set Node {}'s Mode to {}", nodeId, cfgObject.getMode());
786 notifyModeChange(node, cfgObject.isProactive());
791 public Status updateNodeConfig(SwitchConfig switchConfig) {
792 Status status = switchConfig.validate();
793 if (!status.isSuccess()) {
797 Map<String, Property> updateProperties = switchConfig.getNodeProperties();
798 ForwardingMode mode = (ForwardingMode) updateProperties.get(ForwardingMode.name);
800 if (isDefaultContainer) {
801 if (!mode.isValid()) {
802 return new Status(StatusCode.BADREQUEST, "Invalid Forwarding Mode Value");
805 return new Status(StatusCode.NOTACCEPTABLE,
806 "Forwarding Mode modification is allowed only in default container");
810 Description description = (Description) switchConfig.getProperty(Description.propertyName);
811 String nodeId = switchConfig.getNodeId();
812 Node node = Node.fromString(nodeId);
813 NodeDescription nodeDesc = (this.statisticsManager == null) ? null : this.statisticsManager
814 .getNodeDescription(node);
815 String advertisedDesc = (nodeDesc == null) ? "" : nodeDesc.getDescription();
816 if (description != null && description.getValue() != null) {
817 if (description.getValue().isEmpty() || description.getValue().equals(advertisedDesc)) {
818 updateProperties.remove(Description.propertyName);
819 switchConfig = new SwitchConfig(nodeId, updateProperties);
821 // check if description is configured or was published by any other node
822 for (Map.Entry<Node, Map<String, Property>> entry : nodeProps.entrySet()) {
823 Node n = entry.getKey();
824 Description desc = (Description) getNodeProp(n, Description.propertyName);
825 NodeDescription nDesc = (this.statisticsManager == null) ? null : this.statisticsManager
826 .getNodeDescription(n);
827 String advDesc = (nDesc == null) ? "" : nDesc.getDescription();
828 if ((description.equals(desc) || description.getValue().equals(advDesc)) && !node.equals(n)) {
829 return new Status(StatusCode.CONFLICT, "Node name already in use");
835 boolean modeChange = false;
836 SwitchConfig sc = nodeConfigList.get(nodeId);
837 Map<String, Property> prevNodeProperties = new HashMap<String, Property>();
839 if ((mode != null) && mode.isProactive()) {
842 if (!updateProperties.isEmpty()) {
843 if (nodeConfigList.putIfAbsent(nodeId, switchConfig) != null) {
844 return new Status(StatusCode.CONFLICT, "Cluster conflict: Unable to update node configuration");
848 prevNodeProperties = new HashMap<String, Property>(sc.getNodeProperties());
849 ForwardingMode prevMode = (ForwardingMode) sc.getProperty(ForwardingMode.name);
851 if ((prevMode != null) && (prevMode.isProactive())) {
855 if (((prevMode != null) && (prevMode.getValue() != mode.getValue()))
856 || (prevMode == null && mode.isProactive())) {
860 if (updateProperties.isEmpty()) {
861 nodeConfigList.remove(nodeId);
863 if (!nodeConfigList.replace(nodeId, sc, switchConfig)) {
864 return new Status(StatusCode.CONFLICT, "Cluster conflict: Unable to update node configuration");
868 Map<String, Property> propMapCurr = nodeProps.get(node);
869 if (propMapCurr == null) {
870 return new Status(StatusCode.SUCCESS);
872 Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
873 for (Map.Entry<String, Property> entry : prevNodeProperties.entrySet()) {
874 String prop = entry.getKey();
875 if (!updateProperties.containsKey(prop)) {
876 if (prop.equals(Description.propertyName)) {
877 if (!advertisedDesc.isEmpty()) {
878 Property desc = new Description(advertisedDesc);
879 propMap.put(Description.propertyName, desc);
882 } else if (prop.equals(ForwardingMode.name)) {
883 Property defaultMode = new ForwardingMode(ForwardingMode.REACTIVE_FORWARDING);
884 propMap.put(ForwardingMode.name, defaultMode);
887 propMap.remove(prop);
890 propMap.putAll(updateProperties);
891 if (!nodeProps.replace(node, propMapCurr, propMap)) {
892 // TODO rollback using Transactionality
893 return new Status(StatusCode.CONFLICT, "Cluster conflict: Unable to update node configuration");
896 notifyModeChange(node, (mode == null) ? false : mode.isProactive());
898 return new Status(StatusCode.SUCCESS);
902 public Status removeNodeConfig(String nodeId) {
903 if ((nodeId == null) || (nodeId.isEmpty())) {
904 return new Status(StatusCode.BADREQUEST, "nodeId cannot be empty.");
906 Map<String, Property> nodeProperties = getSwitchConfig(nodeId).getNodeProperties();
907 Node node = Node.fromString(nodeId);
908 Map<String, Property> propMapCurr = nodeProps.get(node);
909 if ((propMapCurr != null) && (nodeProperties != null) && (!nodeProperties.isEmpty())) {
910 Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
911 for (Map.Entry<String, Property> entry : nodeProperties.entrySet()) {
912 String prop = entry.getKey();
913 if (prop.equals(Description.propertyName)) {
914 Map<Node, Map<String, Property>> nodeProp = this.inventoryService.getNodeProps();
915 if (nodeProp.get(node) != null) {
916 propMap.put(Description.propertyName, nodeProp.get(node).get(Description.propertyName));
920 propMap.remove(prop);
922 if (!nodeProps.replace(node, propMapCurr, propMap)) {
923 return new Status(StatusCode.CONFLICT, "Cluster conflict: Unable to update node configuration.");
926 if (nodeConfigList != null) {
927 nodeConfigList.remove(nodeId);
929 return new Status(StatusCode.SUCCESS);
933 public Status saveSwitchConfig() {
934 return saveSwitchConfigInternal();
937 public Status saveSwitchConfigInternal() {
938 Status retS = null, retP = null;
939 ObjectWriter objWriter = new ObjectWriter();
941 retS = objWriter.write(new ConcurrentHashMap<String, SubnetConfig>(
942 subnetsConfigList), subnetFileName);
943 retP = objWriter.write(new ConcurrentHashMap<SpanConfig, SpanConfig>(
944 spanConfigList), spanFileName);
945 retS = objWriter.write(new ConcurrentHashMap<String, SwitchConfig>(
946 nodeConfigList), switchConfigFileName);
947 if (retS.equals(retP)) {
948 if (retS.isSuccess()) {
951 return new Status(StatusCode.INTERNALERROR, "Save failed");
954 return new Status(StatusCode.INTERNALERROR, "Partial save failure");
959 public List<SpanConfig> getSpanConfigList() {
960 return new ArrayList<SpanConfig>(spanConfigList.values());
964 public Status addSpanConfig(SpanConfig conf) {
965 // Valid config check
966 if (!conf.isValidConfig()) {
967 String msg = "Invalid Span configuration";
969 return new Status(StatusCode.BADREQUEST, msg);
973 if (spanConfigList.containsKey(conf)) {
974 return new Status(StatusCode.CONFLICT, "Same span config exists");
977 // Update configuration
978 if (spanConfigList.putIfAbsent(conf, conf) == null) {
979 // Update database and notify clients
980 addSpanPorts(conf.getNode(), conf.getPortArrayList());
983 return new Status(StatusCode.SUCCESS);
987 public Status removeSpanConfig(SpanConfig conf) {
988 removeSpanPorts(conf.getNode(), conf.getPortArrayList());
990 // Update configuration
991 spanConfigList.remove(conf);
993 return new Status(StatusCode.SUCCESS);
997 public List<NodeConnector> getSpanPorts(Node node) {
998 List<NodeConnector> ncList = new ArrayList<NodeConnector>();
1000 for (NodeConnector nodeConnector : spanNodeConnectors) {
1001 if (nodeConnector.getNode().equals(node)) {
1002 ncList.add(nodeConnector);
1008 private void addNode(Node node, Set<Property> props) {
1009 log.trace("{} added, props: {}", node, props);
1010 if (nodeProps == null) {
1014 Map<String, Property> propMapCurr = nodeProps.get(node);
1015 Map<String, Property> propMap = (propMapCurr == null) ? new HashMap<String, Property>()
1016 : new HashMap<String, Property>(propMapCurr);
1018 // copy node properties from plugin
1019 if (props != null) {
1020 for (Property prop : props) {
1021 propMap.put(prop.getName(), prop);
1025 boolean proactiveForwarding = false;
1026 // copy node properties from config
1027 if (nodeConfigList != null) {
1028 String nodeId = node.toString();
1029 SwitchConfig conf = nodeConfigList.get(nodeId);
1030 if (conf != null && (conf.getNodeProperties() != null)) {
1031 Map<String, Property> nodeProperties = conf.getNodeProperties();
1032 propMap.putAll(nodeProperties);
1033 if (nodeProperties.get(ForwardingMode.name) != null) {
1034 ForwardingMode mode = (ForwardingMode) nodeProperties.get(ForwardingMode.name);
1035 proactiveForwarding = mode.isProactive();
1040 if (!propMap.containsKey(ForwardingMode.name)) {
1041 Property defaultMode = new ForwardingMode(ForwardingMode.REACTIVE_FORWARDING);
1042 propMap.put(ForwardingMode.name, defaultMode);
1044 boolean result = false;
1045 if (propMapCurr == null) {
1046 if (nodeProps.putIfAbsent(node, propMap) == null) {
1050 result = nodeProps.replace(node, propMapCurr, propMap);
1053 log.debug("Cluster conflict: Conflict while adding the node properties. Node: {} Properties: {}",
1054 node.getID(), props);
1055 addNodeProps(node, propMap);
1058 // check if span ports are configed
1061 // notify node listeners
1062 notifyNode(node, UpdateType.ADDED, propMap);
1064 // notify proactive mode forwarding
1065 if (proactiveForwarding) {
1066 notifyModeChange(node, true);
1070 private void removeNode(Node node) {
1071 log.trace("{} removed", node);
1072 if (nodeProps == null) {
1075 nodeProps.remove(node);
1076 nodeConnectorNames.remove(node);
1077 Set<NodeConnector> removeNodeConnectorSet = new HashSet<NodeConnector>();
1078 for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
1079 NodeConnector nodeConnector = entry.getKey();
1080 if (nodeConnector.getNode().equals(node)) {
1081 removeNodeConnectorSet.add(nodeConnector);
1084 for (NodeConnector nc : removeNodeConnectorSet) {
1085 nodeConnectorProps.remove(nc);
1088 // check if span ports need to be cleaned up
1089 removeSpanPorts(node);
1091 /* notify node listeners */
1092 notifyNode(node, UpdateType.REMOVED, null);
1095 private void updateNode(Node node, Set<Property> props) {
1096 log.trace("{} updated, props: {}", node, props);
1097 if (nodeProps == null || !nodeProps.containsKey(node) ||
1098 props == null || props.isEmpty()) {
1102 Map<String, Property> propMapCurr = nodeProps.get(node);
1103 Map<String, Property> propMap = (propMapCurr == null) ? new HashMap<String, Property>()
1104 : new HashMap<String, Property>(propMapCurr);
1106 // copy node properties from plugin
1107 String nodeId = node.toString();
1108 for (Property prop : props) {
1109 if (nodeConfigList != null) {
1110 SwitchConfig conf = nodeConfigList.get(nodeId);
1111 if (conf != null && (conf.getNodeProperties() != null)
1112 && conf.getNodeProperties().containsKey(prop.getName())) {
1116 propMap.put(prop.getName(), prop);
1119 if (propMapCurr == null) {
1120 if (nodeProps.putIfAbsent(node, propMap) != null) {
1121 log.debug("Cluster conflict: Conflict while updating the node. Node: {} Properties: {}",
1122 node.getID(), props);
1123 addNodeProps(node, propMap);
1126 if (!nodeProps.replace(node, propMapCurr, propMap)) {
1127 log.debug("Cluster conflict: Conflict while updating the node. Node: {} Properties: {}",
1128 node.getID(), props);
1129 addNodeProps(node, propMap);
1133 /* notify node listeners */
1134 notifyNode(node, UpdateType.CHANGED, propMap);
1138 public void updateNode(Node node, UpdateType type, Set<Property> props) {
1139 log.debug("updateNode: {} type {} props {} for container {}",
1140 new Object[] { node, type, props, containerName });
1143 addNode(node, props);
1146 updateNode(node, props);
1157 public void updateNodeConnector(NodeConnector nodeConnector,
1158 UpdateType type, Set<Property> props) {
1159 Map<String, Property> propMap = new HashMap<String, Property>();
1160 boolean update = true;
1162 log.debug("updateNodeConnector: {} type {} props {} for container {}",
1163 new Object[] { nodeConnector, type, props, containerName });
1165 if (nodeConnectorProps == null) {
1171 if (props != null) {
1172 for (Property prop : props) {
1173 addNodeConnectorProp(nodeConnector, prop);
1174 propMap.put(prop.getName(), prop);
1177 addNodeConnectorProp(nodeConnector, null);
1180 addSpanPort(nodeConnector);
1183 if (!nodeConnectorProps.containsKey(nodeConnector) || (props == null)) {
1186 for (Property prop : props) {
1187 addNodeConnectorProp(nodeConnector, prop);
1188 propMap.put(prop.getName(), prop);
1193 if (!nodeConnectorProps.containsKey(nodeConnector)) {
1196 removeNodeConnectorAllProps(nodeConnector);
1198 // clean up span config
1199 removeSpanPort(nodeConnector);
1207 notifyNodeConnector(nodeConnector, type, propMap);
1212 public Set<Node> getNodes() {
1213 return (nodeProps != null) ? new HashSet<Node>(nodeProps.keySet()) : new HashSet<Node>();
1217 public Map<String, Property> getControllerProperties() {
1218 return new HashMap<String, Property>(this.controllerProps);
1222 public Property getControllerProperty(String propertyName) {
1223 if (propertyName != null) {
1224 HashMap<String, Property> propertyMap = new HashMap<String, Property>(this.controllerProps);
1225 return propertyMap.get(propertyName);
1231 public Status setControllerProperty(Property property) {
1232 if (property != null) {
1233 this.controllerProps.put(property.getName(), property);
1234 return new Status(StatusCode.SUCCESS);
1236 return new Status(StatusCode.BADREQUEST, "Invalid property provided when setting property");
1240 public Status removeControllerProperty(String propertyName) {
1241 if (propertyName != null) {
1242 if (this.controllerProps.containsKey(propertyName)) {
1243 this.controllerProps.remove(propertyName);
1244 if (!this.controllerProps.containsKey(propertyName)) {
1245 return new Status(StatusCode.SUCCESS);
1248 String msg = "Unable to remove property " + propertyName + " from Controller";
1249 return new Status(StatusCode.BADREQUEST, msg);
1251 String msg = "Invalid property provided when removing property from Controller";
1252 return new Status(StatusCode.BADREQUEST, msg);
1256 * Returns a copy of a list of properties for a given node
1261 * org.opendaylight.controller.switchmanager.ISwitchManager#getNodeProps
1262 * (org.opendaylight.controller.sal.core.Node)
1265 public Map<String, Property> getNodeProps(Node node) {
1266 Map<String, Property> rv = new HashMap<String, Property>();
1267 if (this.nodeProps != null) {
1268 rv = this.nodeProps.get(node);
1270 /* make a copy of it */
1271 rv = new HashMap<String, Property>(rv);
1278 public Property getNodeProp(Node node, String propName) {
1279 Map<String, Property> propMap = getNodeProps(node);
1280 return (propMap != null) ? propMap.get(propName) : null;
1284 public void setNodeProp(Node node, Property prop) {
1286 for (int i = 0; i <= REPLACE_RETRY; i++) {
1287 /* Get a copy of the property map */
1288 Map<String, Property> propMapCurr = getNodeProps(node);
1289 if (propMapCurr == null) {
1293 Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
1294 propMap.put(prop.getName(), prop);
1296 if (nodeProps.replace(node, propMapCurr, propMap)) {
1299 if (!propMapCurr.get(prop.getName()).equals(nodeProps.get(node).get(prop.getName()))) {
1300 log.debug("Cluster conflict: Unable to add property {} to node {}.", prop.getName(), node.getID());
1304 log.warn("Cluster conflict: Unable to add property {} to node {}.", prop.getName(), node.getID());
1308 public Status removeNodeProp(Node node, String propName) {
1309 for (int i = 0; i <= REPLACE_RETRY; i++) {
1310 Map<String, Property> propMapCurr = getNodeProps(node);
1311 if (propMapCurr != null) {
1312 if (!propMapCurr.containsKey(propName)) {
1313 return new Status(StatusCode.SUCCESS);
1315 Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
1316 propMap.remove(propName);
1317 if (nodeProps.replace(node, propMapCurr, propMap)) {
1318 return new Status(StatusCode.SUCCESS);
1320 if (!propMapCurr.get(propName).equals(nodeProps.get(node).get(propName))) {
1321 String msg = "Cluster conflict: Unable to remove property " + propName + " for node "
1323 return new Status(StatusCode.CONFLICT, msg);
1327 return new Status(StatusCode.SUCCESS);
1330 String msg = "Cluster conflict: Unable to remove property " + propName + " for node " + node.getID();
1331 return new Status(StatusCode.CONFLICT, msg);
1335 public Status removeNodeAllProps(Node node) {
1336 this.nodeProps.remove(node);
1337 return new Status(StatusCode.SUCCESS);
1341 public Set<NodeConnector> getUpNodeConnectors(Node node) {
1342 if (nodeConnectorProps == null) {
1346 Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
1347 for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
1348 NodeConnector nodeConnector = entry.getKey();
1349 if (!nodeConnector.getNode().equals(node)) {
1352 if (isNodeConnectorEnabled(nodeConnector)) {
1353 nodeConnectorSet.add(nodeConnector);
1357 return nodeConnectorSet;
1361 public Set<NodeConnector> getNodeConnectors(Node node) {
1362 if (nodeConnectorProps == null) {
1366 Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
1367 for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
1368 NodeConnector nodeConnector = entry.getKey();
1369 if (!nodeConnector.getNode().equals(node)) {
1372 nodeConnectorSet.add(nodeConnector);
1375 return nodeConnectorSet;
1379 public Set<NodeConnector> getPhysicalNodeConnectors(Node node) {
1380 if (nodeConnectorProps == null) {
1384 Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
1385 for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
1386 NodeConnector nodeConnector = entry.getKey();
1387 if (!nodeConnector.getNode().equals(node)
1388 || isSpecial(nodeConnector)) {
1391 nodeConnectorSet.add(nodeConnector);
1394 return nodeConnectorSet;
1398 public Map<String, Property> getNodeConnectorProps(NodeConnector nodeConnector) {
1399 Map<String, Property> rv = new HashMap<String, Property>();
1400 if (this.nodeConnectorProps != null) {
1401 rv = this.nodeConnectorProps.get(nodeConnector);
1403 rv = new HashMap<String, Property>(rv);
1410 public Property getNodeConnectorProp(NodeConnector nodeConnector,
1412 Map<String, Property> propMap = getNodeConnectorProps(nodeConnector);
1413 return (propMap != null) ? propMap.get(propName) : null;
1416 private byte[] getHardwareMAC() {
1417 Enumeration<NetworkInterface> nis;
1418 byte[] macAddress = null;
1421 nis = NetworkInterface.getNetworkInterfaces();
1422 } catch (SocketException e) {
1423 log.error("Failed to acquire controller MAC: ", e);
1427 while (nis.hasMoreElements()) {
1428 NetworkInterface ni = nis.nextElement();
1430 macAddress = ni.getHardwareAddress();
1431 } catch (SocketException e) {
1432 log.error("Failed to acquire controller MAC: ", e);
1434 if (macAddress != null) {
1438 if (macAddress == null) {
1439 log.warn("Failed to acquire controller MAC: No physical interface found");
1440 // This happens when running controller on windows VM, for example
1441 // Try parsing the OS command output
1447 public byte[] getControllerMAC() {
1448 MacAddress macProperty = (MacAddress)controllerProps.get(MacAddress.name);
1449 return (macProperty == null) ? null : macProperty.getMacAddress();
1453 public NodeConnector getNodeConnector(Node node, String nodeConnectorName) {
1454 if (nodeConnectorNames == null) {
1458 Map<String, NodeConnector> map = nodeConnectorNames.get(node);
1463 return map.get(nodeConnectorName);
1467 * Adds a node connector and its property if any
1469 * @param nodeConnector
1470 * {@link org.opendaylight.controller.sal.core.NodeConnector}
1472 * name of {@link org.opendaylight.controller.sal.core.Property}
1473 * @return success or failed reason
1476 public Status addNodeConnectorProp(NodeConnector nodeConnector,
1478 Map<String, Property> propMapCurr = getNodeConnectorProps(nodeConnector);
1479 Map<String, Property> propMap = (propMapCurr == null) ? new HashMap<String, Property>()
1480 : new HashMap<String, Property>(propMapCurr);
1482 String msg = "Cluster conflict: Unable to add NodeConnector Property.";
1483 // Just add the nodeConnector if prop is not available (in a non-default
1486 if (propMapCurr == null) {
1487 if (nodeConnectorProps.putIfAbsent(nodeConnector, propMap) != null) {
1488 return new Status(StatusCode.CONFLICT, msg);
1491 if (!nodeConnectorProps.replace(nodeConnector, propMapCurr, propMap)) {
1492 return new Status(StatusCode.CONFLICT, msg);
1495 return new Status(StatusCode.SUCCESS);
1498 propMap.put(prop.getName(), prop);
1499 if (propMapCurr == null) {
1500 if (nodeConnectorProps.putIfAbsent(nodeConnector, propMap) != null) {
1501 return new Status(StatusCode.CONFLICT, msg);
1504 if (!nodeConnectorProps.replace(nodeConnector, propMapCurr, propMap)) {
1505 return new Status(StatusCode.CONFLICT, msg);
1509 if (prop.getName().equals(Name.NamePropName)) {
1510 if (nodeConnectorNames != null) {
1511 Node node = nodeConnector.getNode();
1512 Map<String, NodeConnector> mapCurr = nodeConnectorNames.get(node);
1513 Map<String, NodeConnector> map = new HashMap<String, NodeConnector>();
1514 if (mapCurr != null) {
1515 for (Map.Entry<String, NodeConnector> entry : mapCurr.entrySet()) {
1516 String s = entry.getKey();
1518 map.put(s, new NodeConnector(entry.getValue()));
1519 } catch (ConstructionException e) {
1520 log.error("An error occured",e);
1525 map.put(((Name) prop).getValue(), nodeConnector);
1526 if (mapCurr == null) {
1527 if (nodeConnectorNames.putIfAbsent(node, map) != null) {
1528 // TODO: recovery using Transactionality
1529 return new Status(StatusCode.CONFLICT, msg);
1532 if (!nodeConnectorNames.replace(node, mapCurr, map)) {
1533 // TODO: recovery using Transactionality
1534 return new Status(StatusCode.CONFLICT, msg);
1540 return new Status(StatusCode.SUCCESS);
1544 * Removes one property of a node connector
1546 * @param nodeConnector
1547 * {@link org.opendaylight.controller.sal.core.NodeConnector}
1549 * name of {@link org.opendaylight.controller.sal.core.Property}
1550 * @return success or failed reason
1553 public Status removeNodeConnectorProp(NodeConnector nodeConnector, String propName) {
1554 Map<String, Property> propMapCurr = getNodeConnectorProps(nodeConnector);
1556 if (propMapCurr == null) {
1557 /* Nothing to remove */
1558 return new Status(StatusCode.SUCCESS);
1561 Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
1562 propMap.remove(propName);
1563 boolean result = nodeConnectorProps.replace(nodeConnector, propMapCurr, propMap);
1564 String msg = "Cluster conflict: Unable to remove NodeConnector property.";
1566 return new Status(StatusCode.CONFLICT, msg);
1569 if (propName.equals(Name.NamePropName)) {
1570 if (nodeConnectorNames != null) {
1571 Name name = ((Name) getNodeConnectorProp(nodeConnector, Name.NamePropName));
1573 Node node = nodeConnector.getNode();
1574 Map<String, NodeConnector> mapCurr = nodeConnectorNames.get(node);
1575 if (mapCurr != null) {
1576 Map<String, NodeConnector> map = new HashMap<String, NodeConnector>();
1577 for (Map.Entry<String, NodeConnector> entry : mapCurr.entrySet()) {
1578 String s = entry.getKey();
1580 map.put(s, new NodeConnector(entry.getValue()));
1581 } catch (ConstructionException e) {
1582 log.error("An error occured",e);
1585 map.remove(name.getValue());
1586 if (!nodeConnectorNames.replace(node, mapCurr, map)) {
1587 // TODO: recovery using Transactionality
1588 return new Status(StatusCode.CONFLICT, msg);
1595 return new Status(StatusCode.SUCCESS);
1599 * Removes all the properties of a node connector
1601 * @param nodeConnector
1602 * {@link org.opendaylight.controller.sal.core.NodeConnector}
1603 * @return success or failed reason
1606 public Status removeNodeConnectorAllProps(NodeConnector nodeConnector) {
1607 if (nodeConnectorNames != null) {
1608 Name name = ((Name) getNodeConnectorProp(nodeConnector, Name.NamePropName));
1610 Node node = nodeConnector.getNode();
1611 Map<String, NodeConnector> mapCurr = nodeConnectorNames.get(node);
1612 if (mapCurr != null) {
1613 Map<String, NodeConnector> map = new HashMap<String, NodeConnector>();
1614 for (Map.Entry<String, NodeConnector> entry : mapCurr.entrySet()) {
1615 String s = entry.getKey();
1617 map.put(s, new NodeConnector(entry.getValue()));
1618 } catch (ConstructionException e) {
1619 log.error("An error occured",e);
1622 map.remove(name.getValue());
1623 if (map.isEmpty()) {
1624 nodeConnectorNames.remove(node);
1626 if (!nodeConnectorNames.replace(node, mapCurr, map)) {
1627 log.warn("Cluster conflict: Unable remove Name property of nodeconnector {}, skip.",
1628 nodeConnector.getID());
1635 nodeConnectorProps.remove(nodeConnector);
1637 return new Status(StatusCode.SUCCESS);
1641 * Function called by the dependency manager when all the required
1642 * dependencies are satisfied
1645 void init(Component c) {
1646 Dictionary<?, ?> props = c.getServiceProperties();
1647 if (props != null) {
1648 this.containerName = (String) props.get("containerName");
1649 log.trace("Running containerName: {}", this.containerName);
1651 // In the Global instance case the containerName is empty
1652 this.containerName = "";
1654 isDefaultContainer = containerName.equals(GlobalConstants.DEFAULT
1661 * Function called by the dependency manager when at least one dependency
1662 * become unsatisfied or when the component is shutting down because for
1663 * example bundle is being stopped.
1671 * Function called by dependency manager after "init ()" is called and after
1672 * the services provided by the class are registered in the service registry
1677 registerWithOSGIConsole();
1681 * Function called after registered the service in OSGi service registry.
1684 // solicit for existing inventories
1689 * Function called by the dependency manager before the services exported by
1690 * the component are unregistered, this will be followed by a "destroy ()"
1697 public void setInventoryService(IInventoryService service) {
1698 log.trace("Got inventory service set request {}", service);
1699 this.inventoryService = service;
1701 // solicit for existing inventories
1705 public void unsetInventoryService(IInventoryService service) {
1706 log.trace("Got a service UNset request");
1707 this.inventoryService = null;
1709 // clear existing inventories
1713 public void setStatisticsManager(IStatisticsManager statisticsManager) {
1714 log.trace("Got statistics manager set request {}", statisticsManager);
1715 this.statisticsManager = statisticsManager;
1718 public void unsetStatisticsManager(IStatisticsManager statisticsManager) {
1719 log.trace("Got statistics manager UNset request");
1720 this.statisticsManager = null;
1723 public void setSwitchManagerAware(ISwitchManagerAware service) {
1724 log.trace("Got inventory service set request {}", service);
1725 if (this.switchManagerAware != null) {
1726 this.switchManagerAware.add(service);
1729 // bulk update for newly joined
1730 switchManagerAwareNotify(service);
1733 public void unsetSwitchManagerAware(ISwitchManagerAware service) {
1734 log.trace("Got a service UNset request");
1735 if (this.switchManagerAware != null) {
1736 this.switchManagerAware.remove(service);
1740 public void setInventoryListener(IInventoryListener service) {
1741 log.trace("Got inventory listener set request {}", service);
1742 if (this.inventoryListeners != null) {
1743 this.inventoryListeners.add(service);
1746 // bulk update for newly joined
1747 bulkUpdateService(service);
1750 public void unsetInventoryListener(IInventoryListener service) {
1751 log.trace("Got a service UNset request");
1752 if (this.inventoryListeners != null) {
1753 this.inventoryListeners.remove(service);
1757 public void setSpanAware(ISpanAware service) {
1758 log.trace("Got SpanAware set request {}", service);
1759 if (this.spanAware != null) {
1760 this.spanAware.add(service);
1763 // bulk update for newly joined
1764 spanAwareNotify(service);
1767 public void unsetSpanAware(ISpanAware service) {
1768 log.trace("Got a service UNset request");
1769 if (this.spanAware != null) {
1770 this.spanAware.remove(service);
1774 void setClusterContainerService(IClusterContainerServices s) {
1775 log.trace("Cluster Service set");
1776 this.clusterContainerService = s;
1779 void unsetClusterContainerService(IClusterContainerServices s) {
1780 if (this.clusterContainerService == s) {
1781 log.trace("Cluster Service removed!");
1782 this.clusterContainerService = null;
1786 private void getInventories() {
1787 if (inventoryService == null) {
1788 log.trace("inventory service not avaiable");
1792 Map<Node, Map<String, Property>> nodeProp = this.inventoryService.getNodeProps();
1793 for (Map.Entry<Node, Map<String, Property>> entry : nodeProp.entrySet()) {
1794 Node node = entry.getKey();
1795 log.debug("getInventories: {} added for container {}", new Object[] { node, containerName });
1796 Map<String, Property> propMap = entry.getValue();
1797 Set<Property> props = new HashSet<Property>();
1798 for (Property property : propMap.values()) {
1799 props.add(property);
1801 addNode(node, props);
1804 Map<NodeConnector, Map<String, Property>> nodeConnectorProp = this.inventoryService.getNodeConnectorProps();
1805 for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProp.entrySet()) {
1806 Map<String, Property> propMap = entry.getValue();
1807 for (Property property : propMap.values()) {
1808 addNodeConnectorProp(entry.getKey(), property);
1813 private void clearInventories() {
1815 nodeConnectorProps.clear();
1816 nodeConnectorNames.clear();
1817 spanNodeConnectors.clear();
1820 private void notifyNode(Node node, UpdateType type,
1821 Map<String, Property> propMap) {
1822 synchronized (inventoryListeners) {
1823 for (IInventoryListener service : inventoryListeners) {
1824 service.notifyNode(node, type, propMap);
1829 private void notifyNodeConnector(NodeConnector nodeConnector,
1830 UpdateType type, Map<String, Property> propMap) {
1831 synchronized (inventoryListeners) {
1832 for (IInventoryListener service : inventoryListeners) {
1833 service.notifyNodeConnector(nodeConnector, type, propMap);
1839 * For those joined late, bring them up-to-date.
1841 private void switchManagerAwareNotify(ISwitchManagerAware service) {
1842 for (Subnet sub : subnets.values()) {
1843 service.subnetNotify(sub, true);
1846 for (Node node : getNodes()) {
1847 SwitchConfig sc = getSwitchConfig(node.toString());
1848 if ((sc != null) && isDefaultContainer) {
1849 ForwardingMode mode = (ForwardingMode) sc.getProperty(ForwardingMode.name);
1850 service.modeChangeNotify(node, (mode == null) ? false : mode.isProactive());
1855 private void bulkUpdateService(IInventoryListener service) {
1856 Map<String, Property> propMap;
1857 UpdateType type = UpdateType.ADDED;
1859 for (Node node : getNodes()) {
1860 propMap = nodeProps.get(node);
1861 service.notifyNode(node, type, propMap);
1864 for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
1865 NodeConnector nodeConnector = entry.getKey();
1866 propMap = nodeConnectorProps.get(nodeConnector);
1867 service.notifyNodeConnector(nodeConnector, type, propMap);
1871 private void spanAwareNotify(ISpanAware service) {
1872 for (Node node : getNodes()) {
1873 for (SpanConfig conf : getSpanConfigList(node)) {
1874 service.spanUpdate(node, conf.getPortArrayList(), true);
1879 private void registerWithOSGIConsole() {
1880 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
1881 .getBundleContext();
1882 bundleContext.registerService(CommandProvider.class.getName(), this,
1887 public Boolean isNodeConnectorEnabled(NodeConnector nodeConnector) {
1888 if (nodeConnector == null) {
1892 Config config = (Config) getNodeConnectorProp(nodeConnector,
1893 Config.ConfigPropName);
1894 State state = (State) getNodeConnectorProp(nodeConnector,
1895 State.StatePropName);
1896 return ((config != null) && (config.getValue() == Config.ADMIN_UP)
1897 && (state != null) && (state.getValue() == State.EDGE_UP));
1901 public boolean doesNodeConnectorExist(NodeConnector nc) {
1902 return (nc != null && nodeConnectorProps != null
1903 && nodeConnectorProps.containsKey(nc));
1907 public String getHelp() {
1908 StringBuffer help = new StringBuffer();
1909 help.append("---Switch Manager---\n");
1910 help.append("\t pencs <node id> - Print enabled node connectors for a given node\n");
1911 help.append("\t pdm <node id> - Print switch ports in device map\n");
1912 return help.toString();
1915 public void _pencs(CommandInterpreter ci) {
1916 String st = ci.nextArgument();
1918 ci.println("Please enter node id");
1922 Node node = Node.fromString(st);
1924 ci.println("Please enter node id");
1928 Set<NodeConnector> nodeConnectorSet = getUpNodeConnectors(node);
1929 if (nodeConnectorSet == null) {
1932 for (NodeConnector nodeConnector : nodeConnectorSet) {
1933 if (nodeConnector == null) {
1936 ci.println(nodeConnector);
1938 ci.println("Total number of NodeConnectors: " + nodeConnectorSet.size());
1941 public void _pdm(CommandInterpreter ci) {
1942 String st = ci.nextArgument();
1944 ci.println("Please enter node id");
1948 Node node = Node.fromString(st);
1950 ci.println("Please enter node id");
1954 Switch sw = getSwitchByNode(node);
1956 ci.println(" NodeConnector Name");
1958 Set<NodeConnector> nodeConnectorSet = sw.getNodeConnectors();
1959 String nodeConnectorName;
1960 if (nodeConnectorSet != null && nodeConnectorSet.size() > 0) {
1961 for (NodeConnector nodeConnector : nodeConnectorSet) {
1962 Map<String, Property> propMap = getNodeConnectorProps(nodeConnector);
1963 nodeConnectorName = (propMap == null) ? null : ((Name) propMap
1964 .get(Name.NamePropName)).getValue();
1965 if (nodeConnectorName != null) {
1966 Node nd = nodeConnector.getNode();
1967 if (!nd.equals(node)) {
1968 log.debug("node not match {} {}", nd, node);
1970 Map<String, NodeConnector> map = nodeConnectorNames
1973 NodeConnector nc = map.get(nodeConnectorName);
1975 log.debug("no nodeConnector named {}",
1977 } else if (!nc.equals(nodeConnector)) {
1978 log.debug("nodeConnector not match {} {}", nc,
1984 ci.println(nodeConnector
1986 + ((nodeConnectorName == null) ? "" : nodeConnectorName)
1987 + "(" + nodeConnector.getID() + ")");
1989 ci.println("Total number of NodeConnectors: "
1990 + nodeConnectorSet.size());
1995 public byte[] getNodeMAC(Node node) {
1996 MacAddress mac = (MacAddress) this.getNodeProp(node,
1998 return (mac != null) ? mac.getMacAddress() : null;
2002 public boolean isSpecial(NodeConnector p) {
2003 if (p.getType().equals(NodeConnectorIDType.CONTROLLER)
2004 || p.getType().equals(NodeConnectorIDType.ALL)
2005 || p.getType().equals(NodeConnectorIDType.SWSTACK)
2006 || p.getType().equals(NodeConnectorIDType.HWPATH)) {
2013 * Add span configuration to local cache and notify clients
2015 private void addSpanPorts(Node node, List<NodeConnector> nodeConnectors) {
2016 List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
2018 for (NodeConnector nodeConnector : nodeConnectors) {
2019 if (!spanNodeConnectors.contains(nodeConnector)) {
2020 ncLists.add(nodeConnector);
2024 if (ncLists.size() > 0) {
2025 spanNodeConnectors.addAll(ncLists);
2026 notifySpanPortChange(node, ncLists, true);
2030 private void addSpanPorts(Node node) {
2031 for (SpanConfig conf : getSpanConfigList(node)) {
2032 addSpanPorts(node, conf.getPortArrayList());
2036 private void addSpanPort(NodeConnector nodeConnector) {
2037 // only add if span is configured on this nodeConnector
2038 for (SpanConfig conf : getSpanConfigList(nodeConnector.getNode())) {
2039 if (conf.getPortArrayList().contains(nodeConnector)) {
2040 List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
2041 ncLists.add(nodeConnector);
2042 addSpanPorts(nodeConnector.getNode(), ncLists);
2049 * Remove span configuration to local cache and notify clients
2051 private void removeSpanPorts(Node node, List<NodeConnector> nodeConnectors) {
2052 List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
2054 for (NodeConnector nodeConnector : nodeConnectors) {
2055 if (spanNodeConnectors.contains(nodeConnector)) {
2056 ncLists.add(nodeConnector);
2060 if (ncLists.size() > 0) {
2061 spanNodeConnectors.removeAll(ncLists);
2062 notifySpanPortChange(node, ncLists, false);
2066 private void removeSpanPorts(Node node) {
2067 for (SpanConfig conf : getSpanConfigList(node)) {
2068 addSpanPorts(node, conf.getPortArrayList());
2072 private void removeSpanPort(NodeConnector nodeConnector) {
2073 if (spanNodeConnectors.contains(nodeConnector)) {
2074 List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
2075 ncLists.add(nodeConnector);
2076 removeSpanPorts(nodeConnector.getNode(), ncLists);
2080 private void addNodeProps(Node node, Map<String, Property> propMap) {
2081 if (propMap == null) {
2082 propMap = new HashMap<String, Property>();
2084 nodeProps.put(node, propMap);
2088 public Status saveConfiguration() {
2089 return saveSwitchConfig();
2093 * Creates a Name/Tier/Bandwidth/MacAddress(controller property) Property
2094 * object based on given property name and value. Other property types are
2095 * not supported yet.
2098 * Name of the Property
2100 * Value of the Property
2101 * @return {@link org.opendaylight.controller.sal.core.Property}
2104 public Property createProperty(String propName, String propValue) {
2105 if (propName == null) {
2106 log.debug("propName is null");
2109 if (propValue == null) {
2110 log.debug("propValue is null");
2115 if (propName.equalsIgnoreCase(Description.propertyName)) {
2116 return new Description(propValue);
2117 } else if (propName.equalsIgnoreCase(Tier.TierPropName)) {
2118 int tier = Integer.parseInt(propValue);
2119 return new Tier(tier);
2120 } else if (propName.equalsIgnoreCase(Bandwidth.BandwidthPropName)) {
2121 long bw = Long.parseLong(propValue);
2122 return new Bandwidth(bw);
2123 } else if (propName.equalsIgnoreCase(ForwardingMode.name)) {
2124 int mode = Integer.parseInt(propValue);
2125 return new ForwardingMode(mode);
2126 } else if (propName.equalsIgnoreCase(MacAddress.name)){
2127 return new MacAddress(propValue);
2130 log.debug("Not able to create {} property", propName);
2132 } catch (Exception e) {
2133 log.debug("createProperty caught exception {}", e.getMessage());
2140 @SuppressWarnings("deprecation")
2142 public String getNodeDescription(Node node) {
2143 // Check first if user configured a name
2144 SwitchConfig config = getSwitchConfig(node.toString());
2145 if (config != null) {
2146 String configuredDesc = config.getNodeDescription();
2147 if (configuredDesc != null && !configuredDesc.isEmpty()) {
2148 return configuredDesc;
2152 // No name configured by user, get the node advertised name
2153 Description desc = (Description) getNodeProp(node,
2154 Description.propertyName);
2155 return (desc == null /* || desc.getValue().equalsIgnoreCase("none") */) ? ""
2160 public Set<Switch> getConfiguredNotConnectedSwitches() {
2161 Set<Switch> configuredNotConnectedSwitches = new HashSet<Switch>();
2162 if (this.inventoryService == null) {
2163 log.trace("inventory service not avaiable");
2164 return configuredNotConnectedSwitches;
2167 Set<Node> configuredNotConnectedNodes = this.inventoryService.getConfiguredNotConnectedNodes();
2168 if (configuredNotConnectedNodes != null) {
2169 for (Node node : configuredNotConnectedNodes) {
2170 Switch sw = getSwitchByNode(node);
2172 configuredNotConnectedSwitches.add(sw);
2176 return configuredNotConnectedSwitches;