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.Date;
20 import java.util.Dictionary;
21 import java.util.EnumSet;
22 import java.util.Enumeration;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ConcurrentMap;
30 import java.util.concurrent.CopyOnWriteArrayList;
32 import org.apache.felix.dm.Component;
33 import org.eclipse.osgi.framework.console.CommandInterpreter;
34 import org.eclipse.osgi.framework.console.CommandProvider;
35 import org.opendaylight.controller.clustering.services.CacheConfigException;
36 import org.opendaylight.controller.clustering.services.CacheExistException;
37 import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
38 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
39 import org.opendaylight.controller.clustering.services.IClusterServices;
40 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
41 import org.opendaylight.controller.sal.core.Bandwidth;
42 import org.opendaylight.controller.sal.core.Config;
43 import org.opendaylight.controller.sal.core.ConstructionException;
44 import org.opendaylight.controller.sal.core.Description;
45 import org.opendaylight.controller.sal.core.ForwardingMode;
46 import org.opendaylight.controller.sal.core.MacAddress;
47 import org.opendaylight.controller.sal.core.Name;
48 import org.opendaylight.controller.sal.core.Node;
49 import org.opendaylight.controller.sal.core.NodeConnector;
50 import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
51 import org.opendaylight.controller.sal.core.Property;
52 import org.opendaylight.controller.sal.core.State;
53 import org.opendaylight.controller.sal.core.Tier;
54 import org.opendaylight.controller.sal.core.UpdateType;
55 import org.opendaylight.controller.sal.inventory.IInventoryService;
56 import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
57 import org.opendaylight.controller.sal.reader.NodeDescription;
58 import org.opendaylight.controller.sal.utils.GlobalConstants;
59 import org.opendaylight.controller.sal.utils.HexEncode;
60 import org.opendaylight.controller.sal.utils.IObjectReader;
61 import org.opendaylight.controller.sal.utils.ObjectReader;
62 import org.opendaylight.controller.sal.utils.ObjectWriter;
63 import org.opendaylight.controller.sal.utils.Status;
64 import org.opendaylight.controller.sal.utils.StatusCode;
65 import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
66 import org.opendaylight.controller.switchmanager.IInventoryListener;
67 import org.opendaylight.controller.switchmanager.ISpanAware;
68 import org.opendaylight.controller.switchmanager.ISwitchManager;
69 import org.opendaylight.controller.switchmanager.ISwitchManagerAware;
70 import org.opendaylight.controller.switchmanager.SpanConfig;
71 import org.opendaylight.controller.switchmanager.Subnet;
72 import org.opendaylight.controller.switchmanager.SubnetConfig;
73 import org.opendaylight.controller.switchmanager.Switch;
74 import org.opendaylight.controller.switchmanager.SwitchConfig;
75 import org.osgi.framework.BundleContext;
76 import org.osgi.framework.FrameworkUtil;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
81 * The class describes SwitchManager which is the central repository of all the
82 * inventory data including nodes, node connectors, properties attached, Layer3
83 * configurations, Span configurations, node configurations, network device
84 * representations viewed by Controller Web applications. One SwitchManager
85 * instance per container of the network. All the node/nodeConnector properties
86 * are maintained in the default container only.
88 public class SwitchManager implements ISwitchManager,
89 IConfigurationContainerAware, IObjectReader,
90 ICacheUpdateAware<Long, String>, IListenInventoryUpdates,
92 private static Logger log = LoggerFactory.getLogger(SwitchManager.class);
93 private static String ROOT = GlobalConstants.STARTUPHOME.toString();
94 private static final String SAVE = "Save";
95 private String subnetFileName, spanFileName, switchConfigFileName;
96 private final List<NodeConnector> spanNodeConnectors = new CopyOnWriteArrayList<NodeConnector>();
97 // Collection of Subnets keyed by the InetAddress
98 private ConcurrentMap<InetAddress, Subnet> subnets;
99 private ConcurrentMap<String, SubnetConfig> subnetsConfigList;
100 private ConcurrentMap<SpanConfig, SpanConfig> spanConfigList;
101 // manually configured parameters for the node such as name, tier, mode
102 private ConcurrentMap<String, SwitchConfig> nodeConfigList;
103 private ConcurrentMap<Long, String> configSaveEvent;
104 private ConcurrentMap<Node, Map<String, Property>> nodeProps;
105 private ConcurrentMap<NodeConnector, Map<String, Property>> nodeConnectorProps;
106 private ConcurrentMap<Node, Map<String, NodeConnector>> nodeConnectorNames;
107 private ConcurrentMap<String, Property> controllerProps;
108 private IInventoryService inventoryService;
109 private IStatisticsManager statisticsManager;
110 private final Set<ISwitchManagerAware> switchManagerAware = Collections
111 .synchronizedSet(new HashSet<ISwitchManagerAware>());
112 private final Set<IInventoryListener> inventoryListeners = Collections
113 .synchronizedSet(new HashSet<IInventoryListener>());
114 private final Set<ISpanAware> spanAware = Collections.synchronizedSet(new HashSet<ISpanAware>());
115 private static boolean hostRefresh = true;
116 private int hostRetryCount = 5;
117 private IClusterContainerServices clusterContainerService = null;
118 private String containerName = null;
119 private boolean isDefaultContainer = true;
120 private static final int REPLACE_RETRY = 1;
122 public void notifySubnetChange(Subnet sub, boolean add) {
123 synchronized (switchManagerAware) {
124 for (Object subAware : switchManagerAware) {
126 ((ISwitchManagerAware) subAware).subnetNotify(sub, add);
127 } catch (Exception e) {
128 log.error("Failed to notify Subnet change {}",
135 public void notifySpanPortChange(Node node, List<NodeConnector> ports, boolean add) {
136 synchronized (spanAware) {
137 for (Object sa : spanAware) {
139 ((ISpanAware) sa).spanUpdate(node, ports, add);
140 } catch (Exception e) {
141 log.error("Failed to notify Span Interface change {}",
148 private void notifyModeChange(Node node, boolean proactive) {
149 synchronized (switchManagerAware) {
150 for (ISwitchManagerAware service : switchManagerAware) {
152 service.modeChangeNotify(node, proactive);
153 } catch (Exception e) {
154 log.error("Failed to notify Subnet change {}",
161 public void startUp() {
162 String container = this.getContainerName();
163 // Initialize configuration file names
164 subnetFileName = ROOT + "subnets_" + container + ".conf";
165 spanFileName = ROOT + "spanPorts_" + container + ".conf";
166 switchConfigFileName = ROOT + "switchConfig_" + container + ".conf";
168 // Instantiate cluster synced variables
173 * Read startup and build database if we have not already gotten the
174 * configurations synced from another node
176 if (subnetsConfigList.isEmpty()) {
177 loadSubnetConfiguration();
179 if (spanConfigList.isEmpty()) {
180 loadSpanConfiguration();
182 if (nodeConfigList.isEmpty()) {
183 loadSwitchConfiguration();
186 // Add controller MAC, if first node in the cluster
187 if (!controllerProps.containsKey(MacAddress.name)) {
188 byte controllerMac[] = getHardwareMAC();
189 if (controllerMac != null) {
190 Property existing = controllerProps.putIfAbsent(MacAddress.name, new MacAddress(controllerMac));
191 if (existing == null && log.isTraceEnabled()) {
192 log.trace("Container {}: Setting controller MAC address in the cluster: {}", container,
193 HexEncode.bytesToHexStringFormat(controllerMac));
199 public void shutDown() {
202 @SuppressWarnings("deprecation")
203 private void allocateCaches() {
204 if (this.clusterContainerService == null) {
205 this.nonClusterObjectCreate();
206 log.warn("un-initialized clusterContainerService, can't create cache");
211 clusterContainerService.createCache(
212 "switchmanager.subnetsConfigList",
213 EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
214 clusterContainerService.createCache("switchmanager.spanConfigList",
215 EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
216 clusterContainerService.createCache("switchmanager.nodeConfigList",
217 EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
218 clusterContainerService.createCache("switchmanager.subnets",
219 EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
220 clusterContainerService.createCache(
221 "switchmanager.configSaveEvent",
222 EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
223 clusterContainerService.createCache("switchmanager.nodeProps",
224 EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
225 clusterContainerService.createCache(
226 "switchmanager.nodeConnectorProps",
227 EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
228 clusterContainerService.createCache(
229 "switchmanager.nodeConnectorNames",
230 EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
231 clusterContainerService.createCache(
232 "switchmanager.controllerProps",
233 EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
234 } catch (CacheConfigException cce) {
235 log.error("\nCache configuration invalid - check cache mode");
236 } catch (CacheExistException ce) {
237 log.error("\nCache already exits - destroy and recreate if needed");
241 @SuppressWarnings({ "unchecked", "deprecation" })
242 private void retrieveCaches() {
243 if (this.clusterContainerService == null) {
244 log.info("un-initialized clusterContainerService, can't create cache");
248 subnetsConfigList = (ConcurrentMap<String, SubnetConfig>) clusterContainerService
249 .getCache("switchmanager.subnetsConfigList");
250 if (subnetsConfigList == null) {
251 log.error("\nFailed to get cache for subnetsConfigList");
254 spanConfigList = (ConcurrentMap<SpanConfig, SpanConfig>) clusterContainerService
255 .getCache("switchmanager.spanConfigList");
256 if (spanConfigList == null) {
257 log.error("\nFailed to get cache for spanConfigList");
260 nodeConfigList = (ConcurrentMap<String, SwitchConfig>) clusterContainerService
261 .getCache("switchmanager.nodeConfigList");
262 if (nodeConfigList == null) {
263 log.error("\nFailed to get cache for nodeConfigList");
266 subnets = (ConcurrentMap<InetAddress, Subnet>) clusterContainerService
267 .getCache("switchmanager.subnets");
268 if (subnets == null) {
269 log.error("\nFailed to get cache for subnets");
272 configSaveEvent = (ConcurrentMap<Long, String>) clusterContainerService
273 .getCache("switchmanager.configSaveEvent");
274 if (configSaveEvent == null) {
275 log.error("\nFailed to get cache for configSaveEvent");
278 nodeProps = (ConcurrentMap<Node, Map<String, Property>>) clusterContainerService
279 .getCache("switchmanager.nodeProps");
280 if (nodeProps == null) {
281 log.error("\nFailed to get cache for nodeProps");
284 nodeConnectorProps = (ConcurrentMap<NodeConnector, Map<String, Property>>) clusterContainerService
285 .getCache("switchmanager.nodeConnectorProps");
286 if (nodeConnectorProps == null) {
287 log.error("\nFailed to get cache for nodeConnectorProps");
290 nodeConnectorNames = (ConcurrentMap<Node, Map<String, NodeConnector>>) clusterContainerService
291 .getCache("switchmanager.nodeConnectorNames");
292 if (nodeConnectorNames == null) {
293 log.error("\nFailed to get cache for nodeConnectorNames");
296 controllerProps = (ConcurrentMap<String, Property>) clusterContainerService
297 .getCache("switchmanager.controllerProps");
298 if (controllerProps == null) {
299 log.error("\nFailed to get cache for controllerProps");
303 private void nonClusterObjectCreate() {
304 subnetsConfigList = new ConcurrentHashMap<String, SubnetConfig>();
305 spanConfigList = new ConcurrentHashMap<SpanConfig, SpanConfig>();
306 nodeConfigList = new ConcurrentHashMap<String, SwitchConfig>();
307 subnets = new ConcurrentHashMap<InetAddress, Subnet>();
308 configSaveEvent = new ConcurrentHashMap<Long, String>();
309 nodeProps = new ConcurrentHashMap<Node, Map<String, Property>>();
310 nodeConnectorProps = new ConcurrentHashMap<NodeConnector, Map<String, Property>>();
311 nodeConnectorNames = new ConcurrentHashMap<Node, Map<String, NodeConnector>>();
312 controllerProps = new ConcurrentHashMap<String, Property>();
316 public List<SubnetConfig> getSubnetsConfigList() {
317 return new ArrayList<SubnetConfig>(subnetsConfigList.values());
321 public SubnetConfig getSubnetConfig(String subnet) {
322 return subnetsConfigList.get(subnet);
325 private List<SpanConfig> getSpanConfigList(Node node) {
326 List<SpanConfig> confList = new ArrayList<SpanConfig>();
327 String nodeId = node.toString();
328 for (SpanConfig conf : spanConfigList.values()) {
329 if (conf.matchNode(nodeId)) {
336 public List<SwitchConfig> getNodeConfigList() {
337 return new ArrayList<SwitchConfig>(nodeConfigList.values());
341 public SwitchConfig getSwitchConfig(String switchId) {
342 return nodeConfigList.get(switchId);
345 public Switch getSwitchByNode(Node node) {
346 Switch sw = new Switch(node);
348 MacAddress mac = (MacAddress) this.getNodeProp(node,
351 sw.setDataLayerAddress(mac.getMacAddress());
353 Set<NodeConnector> ncSet = getPhysicalNodeConnectors(node);
354 sw.setNodeConnectors(ncSet);
356 List<NodeConnector> ncList = new ArrayList<NodeConnector>();
357 for (NodeConnector nodeConnector : ncSet) {
358 if (spanNodeConnectors.contains(nodeConnector)) {
359 ncList.add(nodeConnector);
362 sw.addSpanPorts(ncList);
368 public List<Switch> getNetworkDevices() {
369 Set<Node> nodeSet = getNodes();
370 List<Switch> swList = new ArrayList<Switch>();
371 if (nodeSet != null) {
372 for (Node node : nodeSet) {
373 swList.add(getSwitchByNode(node));
380 private Status updateConfig(SubnetConfig conf, boolean add) {
382 if(subnetsConfigList.putIfAbsent(conf.getName(), conf) != null) {
383 String msg = "Cluster conflict: Subnet with name " + conf.getName() + "already exists.";
384 return new Status(StatusCode.CONFLICT, msg);
387 subnetsConfigList.remove(conf.getName());
389 return new Status(StatusCode.SUCCESS);
392 private Status updateDatabase(SubnetConfig conf, boolean add) {
394 Subnet subnetCurr = subnets.get(conf.getIPnum());
396 if (subnetCurr == null) {
397 subnet = new Subnet(conf);
399 subnet = subnetCurr.clone();
401 // In case of API3 call we may receive the ports along with the
403 if (!conf.isGlobal()) {
404 Set<NodeConnector> sp = conf.getSubnetNodeConnectors();
405 subnet.addNodeConnectors(sp);
407 boolean putNewSubnet = false;
408 if(subnetCurr == null) {
409 if(subnets.putIfAbsent(conf.getIPnum(), subnet) == null) {
413 putNewSubnet = subnets.replace(conf.getIPnum(), subnetCurr, subnet);
416 String msg = "Cluster conflict: Conflict while adding the subnet " + conf.getIPnum();
417 return new Status(StatusCode.CONFLICT, msg);
420 // Subnet removal case
422 subnets.remove(conf.getIPnum());
424 return new Status(StatusCode.SUCCESS);
427 private Status semanticCheck(SubnetConfig conf) {
428 Subnet newSubnet = new Subnet(conf);
429 Set<InetAddress> IPs = subnets.keySet();
431 return new Status(StatusCode.SUCCESS);
433 for (InetAddress i : IPs) {
434 Subnet existingSubnet = subnets.get(i);
435 if ((existingSubnet != null)
436 && !existingSubnet.isMutualExclusive(newSubnet)) {
437 return new Status(StatusCode.CONFLICT);
440 return new Status(StatusCode.SUCCESS);
443 private Status addRemoveSubnet(SubnetConfig conf, boolean isAdding) {
444 // Valid config check
445 if (!conf.isValidConfig()) {
446 String msg = "Invalid Subnet configuration";
448 return new Status(StatusCode.BADREQUEST, msg);
453 if (subnetsConfigList.containsKey(conf.getName())) {
454 return new Status(StatusCode.CONFLICT,
455 "Subnet with the specified name already configured.");
458 Status rc = semanticCheck(conf);
459 if (!rc.isSuccess()) {
465 Status rc = updateDatabase(conf, isAdding);
467 if (rc.isSuccess()) {
468 // Update Configuration
469 rc = updateConfig(conf, isAdding);
470 if(!rc.isSuccess()) {
471 updateDatabase(conf, (!isAdding));
479 * Adds Subnet configured in GUI or API3
482 public Status addSubnet(SubnetConfig conf) {
483 return this.addRemoveSubnet(conf, true);
487 public Status removeSubnet(SubnetConfig conf) {
488 return this.addRemoveSubnet(conf, false);
492 public Status removeSubnet(String name) {
493 SubnetConfig conf = subnetsConfigList.get(name);
495 return new Status(StatusCode.SUCCESS, "Subnet not present");
497 return this.addRemoveSubnet(conf, false);
501 public Status addPortsToSubnet(String name, String switchPorts) {
502 SubnetConfig confCurr = subnetsConfigList.get(name);
503 if (confCurr == null) {
504 return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
506 if (!confCurr.isValidSwitchPort(switchPorts)) {
507 return new Status(StatusCode.BADREQUEST, "Invalid switchports");
510 Subnet subCurr = subnets.get(confCurr.getIPnum());
511 if (subCurr == null) {
512 log.debug("Cluster conflict: Subnet entry {} is not present in the subnets cache.", confCurr.getIPnum());
513 return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
517 Subnet sub = subCurr.clone();
518 Set<NodeConnector> sp = confCurr.getNodeConnectors(switchPorts);
519 sub.addNodeConnectors(sp);
520 boolean subnetsReplaced = subnets.replace(confCurr.getIPnum(), subCurr, sub);
521 if (!subnetsReplaced) {
522 String msg = "Cluster conflict: Conflict while adding ports to the subnet " + name;
523 return new Status(StatusCode.CONFLICT, msg);
526 // Update Configuration
527 SubnetConfig conf = confCurr.clone();
528 conf.addNodeConnectors(switchPorts);
529 boolean configReplaced = subnetsConfigList.replace(name, confCurr, conf);
530 if (!configReplaced) {
531 // TODO: recovery using Transactionality
532 String msg = "Cluster conflict: Conflict while adding ports to the subnet " + name;
533 return new Status(StatusCode.CONFLICT, msg);
536 return new Status(StatusCode.SUCCESS);
540 public Status removePortsFromSubnet(String name, String switchPorts) {
541 SubnetConfig confCurr = subnetsConfigList.get(name);
542 if (confCurr == null) {
543 return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
546 Subnet subCurr = subnets.get(confCurr.getIPnum());
547 if (subCurr == null) {
548 log.debug("Cluster conflict: Subnet entry {} is not present in the subnets cache.", confCurr.getIPnum());
549 return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
553 Subnet sub = subCurr.clone();
554 Set<NodeConnector> sp = confCurr.getNodeConnectors(switchPorts);
555 sub.deleteNodeConnectors(sp);
556 boolean subnetsReplace = subnets.replace(confCurr.getIPnum(), subCurr, sub);
557 if (!subnetsReplace) {
558 String msg = "Cluster conflict: Conflict while removing ports from the subnet " + name;
559 return new Status(StatusCode.CONFLICT, msg);
562 // Update Configuration
563 SubnetConfig conf = confCurr.clone();
564 conf.removeNodeConnectors(switchPorts);
565 boolean result = subnetsConfigList.replace(name, confCurr, conf);
567 // TODO: recovery using Transactionality
568 String msg = "Cluster conflict: Conflict while removing ports from " + conf;
569 return new Status(StatusCode.CONFLICT, msg);
572 return new Status(StatusCode.SUCCESS);
575 public String getContainerName() {
576 if (containerName == null) {
577 return GlobalConstants.DEFAULT.toString();
579 return containerName;
583 public Subnet getSubnetByNetworkAddress(InetAddress networkAddress) {
585 Set<InetAddress> indices = subnets.keySet();
586 for (InetAddress i : indices) {
587 sub = subnets.get(i);
588 if (sub.isSubnetOf(networkAddress)) {
596 public Object readObject(ObjectInputStream ois)
597 throws FileNotFoundException, IOException, ClassNotFoundException {
598 // Perform the class deserialization locally, from inside the package
599 // where the class is defined
600 return ois.readObject();
603 @SuppressWarnings("unchecked")
604 private void loadSubnetConfiguration() {
605 ObjectReader objReader = new ObjectReader();
606 ConcurrentMap<String, SubnetConfig> confList = (ConcurrentMap<String, SubnetConfig>) objReader
607 .read(this, subnetFileName);
609 if (confList == null) {
613 for (SubnetConfig conf : confList.values()) {
618 @SuppressWarnings("unchecked")
619 private void loadSpanConfiguration() {
620 ObjectReader objReader = new ObjectReader();
621 ConcurrentMap<Integer, SpanConfig> confList = (ConcurrentMap<Integer, SpanConfig>) objReader
622 .read(this, spanFileName);
624 if (confList == null) {
628 for (SpanConfig conf : confList.values()) {
633 @SuppressWarnings("unchecked")
634 private void loadSwitchConfiguration() {
635 ObjectReader objReader = new ObjectReader();
636 ConcurrentMap<String, SwitchConfig> confList = (ConcurrentMap<String, SwitchConfig>) objReader
637 .read(this, switchConfigFileName);
639 if (confList == null) {
643 for (SwitchConfig conf : confList.values()) {
644 updateNodeConfig(conf);
649 public void updateSwitchConfig(SwitchConfig cfgObject) {
650 // update default container only
651 if (!isDefaultContainer) {
655 SwitchConfig sc = nodeConfigList.get(cfgObject.getNodeId());
657 if (nodeConfigList.putIfAbsent(cfgObject.getNodeId(), cfgObject) != null) {
661 if (!nodeConfigList.replace(cfgObject.getNodeId(), sc, cfgObject)) {
666 boolean modeChange = false;
668 if ((sc == null) || !cfgObject.getMode().equals(sc.getMode())) {
672 String nodeId = cfgObject.getNodeId();
673 Node node = Node.fromString(nodeId);
674 Map<String, Property> propMapCurr = nodeProps.get(node);
675 if (propMapCurr == null) {
678 Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
679 Property desc = new Description(cfgObject.getNodeDescription());
680 propMap.put(desc.getName(), desc);
681 Property tier = new Tier(Integer.parseInt(cfgObject.getTier()));
682 propMap.put(tier.getName(), tier);
684 if (!nodeProps.replace(node, propMapCurr, propMap)) {
685 // TODO rollback using Transactionality
689 log.info("Set Node {}'s Mode to {}", nodeId, cfgObject.getMode());
692 notifyModeChange(node, cfgObject.isProactive());
697 public Status updateNodeConfig(SwitchConfig switchConfig) {
698 Status status = switchConfig.validate();
699 if (!status.isSuccess()) {
703 Map<String, Property> updateProperties = switchConfig.getNodeProperties();
704 ForwardingMode mode = (ForwardingMode) updateProperties.get(ForwardingMode.name);
706 if (isDefaultContainer) {
707 if (!mode.isValid()) {
708 return new Status(StatusCode.BADREQUEST, "Invalid Forwarding Mode Value");
711 return new Status(StatusCode.NOTACCEPTABLE,
712 "Forwarding Mode modification is allowed only in default container");
716 Description description = (Description) switchConfig.getProperty(Description.propertyName);
717 String nodeId = switchConfig.getNodeId();
718 Node node = Node.fromString(nodeId);
719 NodeDescription nodeDesc = (this.statisticsManager == null) ? null : this.statisticsManager
720 .getNodeDescription(node);
721 String advertisedDesc = (nodeDesc == null) ? "" : nodeDesc.getDescription();
722 if (description != null && description.getValue() != null) {
723 if (description.getValue().isEmpty() || description.getValue().equals(advertisedDesc)) {
724 updateProperties.remove(Description.propertyName);
725 switchConfig = new SwitchConfig(nodeId, updateProperties);
727 // check if description is configured or was published by any other node
728 for (Node n : nodeProps.keySet()) {
729 Description desc = (Description) getNodeProp(n, Description.propertyName);
730 NodeDescription nDesc = (this.statisticsManager == null) ? null : this.statisticsManager
731 .getNodeDescription(n);
732 String advDesc = (nDesc == null) ? "" : nDesc.getDescription();
733 if ((description.equals(desc) || description.getValue().equals(advDesc)) && !node.equals(n)) {
734 return new Status(StatusCode.CONFLICT, "Node name already in use");
740 boolean modeChange = false;
741 SwitchConfig sc = nodeConfigList.get(nodeId);
742 Map<String, Property> prevNodeProperties = new HashMap<String, Property>();
744 if ((mode != null) && mode.isProactive()) {
747 if (!updateProperties.isEmpty()) {
748 if (nodeConfigList.putIfAbsent(nodeId, switchConfig) != null) {
749 return new Status(StatusCode.CONFLICT, "Cluster conflict: Unable to update node configuration");
753 prevNodeProperties = new HashMap<String, Property>(sc.getNodeProperties());
754 ForwardingMode prevMode = (ForwardingMode) sc.getProperty(ForwardingMode.name);
756 if ((prevMode != null) && (prevMode.isProactive())) {
760 if (((prevMode != null) && (prevMode.getValue() != mode.getValue()))
761 || (prevMode == null && mode.isProactive())) {
765 if (updateProperties.isEmpty()) {
766 nodeConfigList.remove(nodeId);
768 if (!nodeConfigList.replace(nodeId, sc, switchConfig)) {
769 return new Status(StatusCode.CONFLICT, "Cluster conflict: Unable to update node configuration");
773 Map<String, Property> propMapCurr = nodeProps.get(node);
774 if (propMapCurr == null) {
775 return new Status(StatusCode.SUCCESS);
777 Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
778 for (String prop : prevNodeProperties.keySet()) {
779 if (!updateProperties.containsKey(prop)) {
780 if (prop.equals(Description.propertyName)) {
781 if (!advertisedDesc.isEmpty()) {
782 Property desc = new Description(advertisedDesc);
783 propMap.put(Description.propertyName, desc);
787 propMap.remove(prop);
790 propMap.putAll(updateProperties);
791 if (!nodeProps.replace(node, propMapCurr, propMap)) {
792 // TODO rollback using Transactionality
793 return new Status(StatusCode.CONFLICT, "Cluster conflict: Unable to update node configuration");
796 notifyModeChange(node, (mode == null) ? false : mode.isProactive());
798 return new Status(StatusCode.SUCCESS);
802 public Status removeNodeConfig(String nodeId) {
803 if ((nodeId == null) || (nodeId.isEmpty())) {
804 return new Status(StatusCode.BADREQUEST, "nodeId cannot be empty.");
806 Map<String, Property> nodeProperties = getSwitchConfig(nodeId).getNodeProperties();
807 Node node = Node.fromString(nodeId);
808 Map<String, Property> propMapCurr = nodeProps.get(node);
809 if ((propMapCurr != null) && (nodeProperties != null) && (!nodeProperties.isEmpty())) {
810 Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
811 for (String prop : nodeProperties.keySet()) {
812 if (prop.equals(Description.propertyName)) {
813 Map<Node, Map<String, Property>> nodeProp = this.inventoryService.getNodeProps();
814 if (nodeProp.get(node) != null) {
815 propMap.put(Description.propertyName, nodeProp.get(node).get(Description.propertyName));
819 propMap.remove(prop);
821 if (!nodeProps.replace(node, propMapCurr, propMap)) {
822 return new Status(StatusCode.CONFLICT, "Cluster conflict: Unable to update node configuration.");
825 if (nodeConfigList != null) {
826 nodeConfigList.remove(nodeId);
828 return new Status(StatusCode.SUCCESS);
832 public Status saveSwitchConfig() {
833 // Publish the save config event to the cluster nodes
834 configSaveEvent.put(new Date().getTime(), SAVE);
835 return saveSwitchConfigInternal();
838 public Status saveSwitchConfigInternal() {
839 Status retS = null, retP = null;
840 ObjectWriter objWriter = new ObjectWriter();
842 retS = objWriter.write(new ConcurrentHashMap<String, SubnetConfig>(
843 subnetsConfigList), subnetFileName);
844 retP = objWriter.write(new ConcurrentHashMap<SpanConfig, SpanConfig>(
845 spanConfigList), spanFileName);
846 retS = objWriter.write(new ConcurrentHashMap<String, SwitchConfig>(
847 nodeConfigList), switchConfigFileName);
848 if (retS.equals(retP)) {
849 if (retS.isSuccess()) {
852 return new Status(StatusCode.INTERNALERROR, "Save failed");
855 return new Status(StatusCode.INTERNALERROR, "Partial save failure");
860 public List<SpanConfig> getSpanConfigList() {
861 return new ArrayList<SpanConfig>(spanConfigList.values());
865 public Status addSpanConfig(SpanConfig conf) {
866 // Valid config check
867 if (!conf.isValidConfig()) {
868 String msg = "Invalid Span configuration";
870 return new Status(StatusCode.BADREQUEST, msg);
874 if (spanConfigList.containsKey(conf)) {
875 return new Status(StatusCode.CONFLICT, "Same span config exists");
878 // Update configuration
879 if (spanConfigList.putIfAbsent(conf, conf) == null) {
880 // Update database and notify clients
881 addSpanPorts(conf.getNode(), conf.getPortArrayList());
884 return new Status(StatusCode.SUCCESS);
888 public Status removeSpanConfig(SpanConfig conf) {
889 removeSpanPorts(conf.getNode(), conf.getPortArrayList());
891 // Update configuration
892 spanConfigList.remove(conf);
894 return new Status(StatusCode.SUCCESS);
898 public List<NodeConnector> getSpanPorts(Node node) {
899 List<NodeConnector> ncList = new ArrayList<NodeConnector>();
901 for (NodeConnector nodeConnector : spanNodeConnectors) {
902 if (nodeConnector.getNode().equals(node)) {
903 ncList.add(nodeConnector);
910 public void entryCreated(Long key, String cacheName, boolean local) {
914 public void entryUpdated(Long key, String newValue, String cacheName,
915 boolean originLocal) {
916 saveSwitchConfigInternal();
920 public void entryDeleted(Long key, String cacheName, boolean originLocal) {
923 private void addNode(Node node, Set<Property> props) {
924 log.trace("{} added, props: {}", node, props);
925 if (nodeProps == null) {
929 Map<String, Property> propMapCurr = nodeProps.get(node);
930 Map<String, Property> propMap = (propMapCurr == null) ? new HashMap<String, Property>()
931 : new HashMap<String, Property>(propMapCurr);
933 // copy node properties from plugin
935 for (Property prop : props) {
936 propMap.put(prop.getName(), prop);
940 // copy node properties from config
941 boolean proactiveForwarding = false;
942 if (nodeConfigList != null) {
943 String nodeId = node.toString();
944 SwitchConfig conf = nodeConfigList.get(nodeId);
945 if (conf != null && (conf.getNodeProperties() != null)) {
946 Map<String, Property> nodeProperties = conf.getNodeProperties();
947 propMap.putAll(nodeProperties);
948 if (nodeProperties.get(ForwardingMode.name) != null) {
949 ForwardingMode mode = (ForwardingMode) nodeProperties.get(ForwardingMode.name);
950 proactiveForwarding = mode.isProactive();
955 boolean result = false;
956 if (propMapCurr == null) {
957 if (nodeProps.putIfAbsent(node, propMap) == null) {
961 result = nodeProps.replace(node, propMapCurr, propMap);
964 log.debug("Cluster conflict: Conflict while adding the node properties. Node: {} Properties: {}",
965 node.getID(), props);
966 addNodeProps(node, propMap);
969 // check if span ports are configed
972 // notify node listeners
973 notifyNode(node, UpdateType.ADDED, propMap);
975 // notify proactive mode forwarding
976 if (proactiveForwarding) {
977 notifyModeChange(node, true);
981 private void removeNode(Node node) {
982 log.trace("{} removed", node);
983 if (nodeProps == null) {
986 nodeProps.remove(node);
988 // check if span ports need to be cleaned up
989 removeSpanPorts(node);
991 /* notify node listeners */
992 notifyNode(node, UpdateType.REMOVED, null);
995 private void updateNode(Node node, Set<Property> props) {
996 log.trace("{} updated, props: {}", node, props);
997 if (nodeProps == null || !nodeProps.containsKey(node) ||
998 props == null || props.isEmpty()) {
1002 Map<String, Property> propMapCurr = nodeProps.get(node);
1003 Map<String, Property> propMap = (propMapCurr == null) ? new HashMap<String, Property>()
1004 : new HashMap<String, Property>(propMapCurr);
1006 // copy node properties from plugin
1007 String nodeId = node.toString();
1008 for (Property prop : props) {
1009 if (nodeConfigList != null) {
1010 SwitchConfig conf = nodeConfigList.get(nodeId);
1011 if (conf != null && (conf.getNodeProperties() != null)
1012 && conf.getNodeProperties().containsKey(prop.getName())) {
1016 propMap.put(prop.getName(), prop);
1019 if (propMapCurr == null) {
1020 if (nodeProps.putIfAbsent(node, propMap) != null) {
1021 log.debug("Cluster conflict: Conflict while updating the node. Node: {} Properties: {}",
1022 node.getID(), props);
1023 addNodeProps(node, propMap);
1026 if (!nodeProps.replace(node, propMapCurr, propMap)) {
1027 log.debug("Cluster conflict: Conflict while updating the node. Node: {} Properties: {}",
1028 node.getID(), props);
1029 addNodeProps(node, propMap);
1033 /* notify node listeners */
1034 notifyNode(node, UpdateType.CHANGED, propMap);
1038 public void updateNode(Node node, UpdateType type, Set<Property> props) {
1039 log.debug("updateNode: {} type {} props {} for container {}",
1040 new Object[] { node, type, props, containerName });
1043 addNode(node, props);
1046 updateNode(node, props);
1057 public void updateNodeConnector(NodeConnector nodeConnector,
1058 UpdateType type, Set<Property> props) {
1059 Map<String, Property> propMap = new HashMap<String, Property>();
1061 log.debug("updateNodeConnector: {} type {} props {} for container {}",
1062 new Object[] { nodeConnector, type, props, containerName });
1064 if (nodeConnectorProps == null) {
1071 if (props != null) {
1072 for (Property prop : props) {
1073 addNodeConnectorProp(nodeConnector, prop);
1074 propMap.put(prop.getName(), prop);
1077 addNodeConnectorProp(nodeConnector, null);
1080 addSpanPort(nodeConnector);
1083 removeNodeConnectorAllProps(nodeConnector);
1085 // clean up span config
1086 removeSpanPort(nodeConnector);
1092 notifyNodeConnector(nodeConnector, type, propMap);
1096 public Set<Node> getNodes() {
1097 return (nodeProps != null) ? new HashSet<Node>(nodeProps.keySet())
1102 * Returns a copy of a list of properties for a given node
1107 * org.opendaylight.controller.switchmanager.ISwitchManager#getNodeProps
1108 * (org.opendaylight.controller.sal.core.Node)
1111 public Map<String, Property> getNodeProps(Node node) {
1112 Map<String, Property> rv = new HashMap<String, Property>();
1113 if (this.nodeProps != null) {
1114 rv = this.nodeProps.get(node);
1116 /* make a copy of it */
1117 rv = new HashMap<String, Property>(rv);
1124 public Property getNodeProp(Node node, String propName) {
1125 Map<String, Property> propMap = getNodeProps(node);
1126 return (propMap != null) ? propMap.get(propName) : null;
1130 public void setNodeProp(Node node, Property prop) {
1132 for (int i = 0; i <= REPLACE_RETRY; i++) {
1133 /* Get a copy of the property map */
1134 Map<String, Property> propMapCurr = getNodeProps(node);
1135 if (propMapCurr == null) {
1139 Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
1140 propMap.put(prop.getName(), prop);
1142 if (nodeProps.replace(node, propMapCurr, propMap)) {
1145 if (!propMapCurr.get(prop.getName()).equals(nodeProps.get(node).get(prop.getName()))) {
1146 log.debug("Cluster conflict: Unable to add property {} to node {}.", prop.getName(), node.getID());
1150 log.warn("Cluster conflict: Unable to add property {} to node {}.", prop.getName(), node.getID());
1154 public Status removeNodeProp(Node node, String propName) {
1155 for (int i = 0; i <= REPLACE_RETRY; i++) {
1156 Map<String, Property> propMapCurr = getNodeProps(node);
1157 if (propMapCurr != null) {
1158 if (!propMapCurr.containsKey(propName)) {
1159 return new Status(StatusCode.SUCCESS);
1161 Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
1162 propMap.remove(propName);
1163 if (nodeProps.replace(node, propMapCurr, propMap)) {
1164 return new Status(StatusCode.SUCCESS);
1166 if (!propMapCurr.get(propName).equals(nodeProps.get(node).get(propName))) {
1167 String msg = "Cluster conflict: Unable to remove property " + propName + " for node "
1169 return new Status(StatusCode.CONFLICT, msg);
1173 return new Status(StatusCode.SUCCESS);
1176 String msg = "Cluster conflict: Unable to remove property " + propName + " for node " + node.getID();
1177 return new Status(StatusCode.CONFLICT, msg);
1181 public Status removeNodeAllProps(Node node) {
1182 this.nodeProps.remove(node);
1183 return new Status(StatusCode.SUCCESS);
1187 public Set<NodeConnector> getUpNodeConnectors(Node node) {
1188 if (nodeConnectorProps == null) {
1192 Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
1193 for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
1194 if (!nodeConnector.getNode().equals(node)) {
1197 if (isNodeConnectorEnabled(nodeConnector)) {
1198 nodeConnectorSet.add(nodeConnector);
1202 return nodeConnectorSet;
1206 public Set<NodeConnector> getNodeConnectors(Node node) {
1207 if (nodeConnectorProps == null) {
1211 Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
1212 for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
1213 if (!nodeConnector.getNode().equals(node)) {
1216 nodeConnectorSet.add(nodeConnector);
1219 return nodeConnectorSet;
1223 public Set<NodeConnector> getPhysicalNodeConnectors(Node node) {
1224 if (nodeConnectorProps == null) {
1228 Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
1229 for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
1230 if (!nodeConnector.getNode().equals(node)
1231 || isSpecial(nodeConnector)) {
1234 nodeConnectorSet.add(nodeConnector);
1237 return nodeConnectorSet;
1241 public Map<String, Property> getNodeConnectorProps(NodeConnector nodeConnector) {
1242 Map<String, Property> rv = new HashMap<String, Property>();
1243 if (this.nodeConnectorProps != null) {
1244 rv = this.nodeConnectorProps.get(nodeConnector);
1246 rv = new HashMap<String, Property>(rv);
1253 public Property getNodeConnectorProp(NodeConnector nodeConnector,
1255 Map<String, Property> propMap = getNodeConnectorProps(nodeConnector);
1256 return (propMap != null) ? propMap.get(propName) : null;
1259 private byte[] getHardwareMAC() {
1260 Enumeration<NetworkInterface> nis;
1261 byte[] macAddress = null;
1264 nis = NetworkInterface.getNetworkInterfaces();
1265 } catch (SocketException e) {
1266 log.error("Failed to acquire controller MAC: ", e);
1270 while (nis.hasMoreElements()) {
1271 NetworkInterface ni = nis.nextElement();
1273 macAddress = ni.getHardwareAddress();
1274 } catch (SocketException e) {
1275 log.error("Failed to acquire controller MAC: ", e);
1277 if (macAddress != null) {
1281 if (macAddress == null) {
1282 log.warn("Failed to acquire controller MAC: No physical interface found");
1283 // This happens when running controller on windows VM, for example
1284 // Try parsing the OS command output
1290 public byte[] getControllerMAC() {
1291 MacAddress macProperty = (MacAddress)controllerProps.get(MacAddress.name);
1292 return (macProperty == null) ? null : macProperty.getMacAddress();
1296 public boolean isHostRefreshEnabled() {
1301 public int getHostRetryCount() {
1302 return hostRetryCount;
1306 public NodeConnector getNodeConnector(Node node, String nodeConnectorName) {
1307 if (nodeConnectorNames == null) {
1311 Map<String, NodeConnector> map = nodeConnectorNames.get(node);
1316 return map.get(nodeConnectorName);
1320 * Adds a node connector and its property if any
1322 * @param nodeConnector
1323 * {@link org.opendaylight.controller.sal.core.NodeConnector}
1325 * name of {@link org.opendaylight.controller.sal.core.Property}
1326 * @return success or failed reason
1329 public Status addNodeConnectorProp(NodeConnector nodeConnector,
1331 Map<String, Property> propMapCurr = getNodeConnectorProps(nodeConnector);
1332 Map<String, Property> propMap = (propMapCurr == null) ? new HashMap<String, Property>()
1333 : new HashMap<String, Property>(propMapCurr);
1335 String msg = "Cluster conflict: Unable to add NodeConnector Property.";
1336 // Just add the nodeConnector if prop is not available (in a non-default
1339 if (propMapCurr == null) {
1340 if (nodeConnectorProps.putIfAbsent(nodeConnector, propMap) != null) {
1341 return new Status(StatusCode.CONFLICT, msg);
1344 if (!nodeConnectorProps.replace(nodeConnector, propMapCurr, propMap)) {
1345 return new Status(StatusCode.CONFLICT, msg);
1348 return new Status(StatusCode.SUCCESS);
1351 propMap.put(prop.getName(), prop);
1352 if (propMapCurr == null) {
1353 if (nodeConnectorProps.putIfAbsent(nodeConnector, propMap) != null) {
1354 return new Status(StatusCode.CONFLICT, msg);
1357 if (!nodeConnectorProps.replace(nodeConnector, propMapCurr, propMap)) {
1358 return new Status(StatusCode.CONFLICT, msg);
1362 if (prop.getName().equals(Name.NamePropName)) {
1363 if (nodeConnectorNames != null) {
1364 Node node = nodeConnector.getNode();
1365 Map<String, NodeConnector> mapCurr = nodeConnectorNames.get(node);
1366 Map<String, NodeConnector> map = new HashMap<String, NodeConnector>();
1367 if (mapCurr != null) {
1368 for (String s : mapCurr.keySet()) {
1370 map.put(s, new NodeConnector(mapCurr.get(s)));
1371 } catch (ConstructionException e) {
1372 e.printStackTrace();
1377 map.put(((Name) prop).getValue(), nodeConnector);
1378 if (mapCurr == null) {
1379 if (nodeConnectorNames.putIfAbsent(node, map) != null) {
1380 // TODO: recovery using Transactionality
1381 return new Status(StatusCode.CONFLICT, msg);
1384 if (!nodeConnectorNames.replace(node, mapCurr, map)) {
1385 // TODO: recovery using Transactionality
1386 return new Status(StatusCode.CONFLICT, msg);
1392 return new Status(StatusCode.SUCCESS);
1396 * Removes one property of a node connector
1398 * @param nodeConnector
1399 * {@link org.opendaylight.controller.sal.core.NodeConnector}
1401 * name of {@link org.opendaylight.controller.sal.core.Property}
1402 * @return success or failed reason
1405 public Status removeNodeConnectorProp(NodeConnector nodeConnector, String propName) {
1406 Map<String, Property> propMapCurr = getNodeConnectorProps(nodeConnector);
1408 if (propMapCurr == null) {
1409 /* Nothing to remove */
1410 return new Status(StatusCode.SUCCESS);
1413 Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
1414 propMap.remove(propName);
1415 boolean result = nodeConnectorProps.replace(nodeConnector, propMapCurr, propMap);
1416 String msg = "Cluster conflict: Unable to remove NodeConnector property.";
1418 return new Status(StatusCode.CONFLICT, msg);
1421 if (propName.equals(Name.NamePropName)) {
1422 if (nodeConnectorNames != null) {
1423 Name name = ((Name) getNodeConnectorProp(nodeConnector, Name.NamePropName));
1425 Node node = nodeConnector.getNode();
1426 Map<String, NodeConnector> mapCurr = nodeConnectorNames.get(node);
1427 if (mapCurr != null) {
1428 Map<String, NodeConnector> map = new HashMap<String, NodeConnector>();
1429 for (String s : mapCurr.keySet()) {
1431 map.put(s, new NodeConnector(mapCurr.get(s)));
1432 } catch (ConstructionException e) {
1433 e.printStackTrace();
1436 map.remove(name.getValue());
1437 if (!nodeConnectorNames.replace(node, mapCurr, map)) {
1438 // TODO: recovery using Transactionality
1439 return new Status(StatusCode.CONFLICT, msg);
1446 return new Status(StatusCode.SUCCESS);
1450 * Removes all the properties of a node connector
1452 * @param nodeConnector
1453 * {@link org.opendaylight.controller.sal.core.NodeConnector}
1454 * @return success or failed reason
1457 public Status removeNodeConnectorAllProps(NodeConnector nodeConnector) {
1458 if (nodeConnectorNames != null) {
1459 Name name = ((Name) getNodeConnectorProp(nodeConnector, Name.NamePropName));
1461 Node node = nodeConnector.getNode();
1462 Map<String, NodeConnector> mapCurr = nodeConnectorNames.get(node);
1463 if (mapCurr != null) {
1464 Map<String, NodeConnector> map = new HashMap<String, NodeConnector>();
1465 for (String s : mapCurr.keySet()) {
1467 map.put(s, new NodeConnector(mapCurr.get(s)));
1468 } catch (ConstructionException e) {
1469 e.printStackTrace();
1472 map.remove(name.getValue());
1473 if (map.isEmpty()) {
1474 nodeConnectorNames.remove(node);
1476 if (!nodeConnectorNames.replace(node, mapCurr, map)) {
1477 log.warn("Cluster conflict: Unable remove Name property of nodeconnector {}, skip.",
1478 nodeConnector.getID());
1485 nodeConnectorProps.remove(nodeConnector);
1487 return new Status(StatusCode.SUCCESS);
1491 * Function called by the dependency manager when all the required
1492 * dependencies are satisfied
1495 void init(Component c) {
1496 Dictionary<?, ?> props = c.getServiceProperties();
1497 if (props != null) {
1498 this.containerName = (String) props.get("containerName");
1499 log.trace("Running containerName: {}", this.containerName);
1501 // In the Global instance case the containerName is empty
1502 this.containerName = "";
1504 isDefaultContainer = containerName.equals(GlobalConstants.DEFAULT
1511 * Function called by the dependency manager when at least one dependency
1512 * become unsatisfied or when the component is shutting down because for
1513 * example bundle is being stopped.
1521 * Function called by dependency manager after "init ()" is called and after
1522 * the services provided by the class are registered in the service registry
1527 registerWithOSGIConsole();
1531 * Function called after registered the service in OSGi service registry.
1534 // solicit for existing inventories
1539 * Function called by the dependency manager before the services exported by
1540 * the component are unregistered, this will be followed by a "destroy ()"
1547 public void setInventoryService(IInventoryService service) {
1548 log.trace("Got inventory service set request {}", service);
1549 this.inventoryService = service;
1551 // solicit for existing inventories
1555 public void unsetInventoryService(IInventoryService service) {
1556 log.trace("Got a service UNset request");
1557 this.inventoryService = null;
1559 // clear existing inventories
1563 public void setStatisticsManager(IStatisticsManager statisticsManager) {
1564 log.trace("Got statistics manager set request {}", statisticsManager);
1565 this.statisticsManager = statisticsManager;
1568 public void unsetStatisticsManager(IStatisticsManager statisticsManager) {
1569 log.trace("Got statistics manager UNset request");
1570 this.statisticsManager = null;
1573 public void setSwitchManagerAware(ISwitchManagerAware service) {
1574 log.trace("Got inventory service set request {}", service);
1575 if (this.switchManagerAware != null) {
1576 this.switchManagerAware.add(service);
1579 // bulk update for newly joined
1580 switchManagerAwareNotify(service);
1583 public void unsetSwitchManagerAware(ISwitchManagerAware service) {
1584 log.trace("Got a service UNset request");
1585 if (this.switchManagerAware != null) {
1586 this.switchManagerAware.remove(service);
1590 public void setInventoryListener(IInventoryListener service) {
1591 log.trace("Got inventory listener set request {}", service);
1592 if (this.inventoryListeners != null) {
1593 this.inventoryListeners.add(service);
1596 // bulk update for newly joined
1597 bulkUpdateService(service);
1600 public void unsetInventoryListener(IInventoryListener service) {
1601 log.trace("Got a service UNset request");
1602 if (this.inventoryListeners != null) {
1603 this.inventoryListeners.remove(service);
1607 public void setSpanAware(ISpanAware service) {
1608 log.trace("Got SpanAware set request {}", service);
1609 if (this.spanAware != null) {
1610 this.spanAware.add(service);
1613 // bulk update for newly joined
1614 spanAwareNotify(service);
1617 public void unsetSpanAware(ISpanAware service) {
1618 log.trace("Got a service UNset request");
1619 if (this.spanAware != null) {
1620 this.spanAware.remove(service);
1624 void setClusterContainerService(IClusterContainerServices s) {
1625 log.trace("Cluster Service set");
1626 this.clusterContainerService = s;
1629 void unsetClusterContainerService(IClusterContainerServices s) {
1630 if (this.clusterContainerService == s) {
1631 log.trace("Cluster Service removed!");
1632 this.clusterContainerService = null;
1636 private void getInventories() {
1637 if (inventoryService == null) {
1638 log.trace("inventory service not avaiable");
1642 Map<Node, Map<String, Property>> nodeProp = this.inventoryService.getNodeProps();
1643 for (Map.Entry<Node, Map<String, Property>> entry : nodeProp.entrySet()) {
1644 Node node = entry.getKey();
1645 log.debug("getInventories: {} added for container {}", new Object[] { node, containerName });
1646 Map<String, Property> propMap = entry.getValue();
1647 Set<Property> props = new HashSet<Property>();
1648 for (Property property : propMap.values()) {
1649 props.add(property);
1651 addNode(node, props);
1654 Map<NodeConnector, Map<String, Property>> nodeConnectorProp = this.inventoryService.getNodeConnectorProps();
1655 for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProp.entrySet()) {
1656 Map<String, Property> propMap = entry.getValue();
1657 for (Property property : propMap.values()) {
1658 addNodeConnectorProp(entry.getKey(), property);
1663 private void clearInventories() {
1665 nodeConnectorProps.clear();
1666 nodeConnectorNames.clear();
1667 spanNodeConnectors.clear();
1670 private void notifyNode(Node node, UpdateType type,
1671 Map<String, Property> propMap) {
1672 synchronized (inventoryListeners) {
1673 for (IInventoryListener service : inventoryListeners) {
1674 service.notifyNode(node, type, propMap);
1679 private void notifyNodeConnector(NodeConnector nodeConnector,
1680 UpdateType type, Map<String, Property> propMap) {
1681 synchronized (inventoryListeners) {
1682 for (IInventoryListener service : inventoryListeners) {
1683 service.notifyNodeConnector(nodeConnector, type, propMap);
1689 * For those joined late, bring them up-to-date.
1691 private void switchManagerAwareNotify(ISwitchManagerAware service) {
1692 for (Subnet sub : subnets.values()) {
1693 service.subnetNotify(sub, true);
1696 for (Node node : getNodes()) {
1697 SwitchConfig sc = getSwitchConfig(node.toString());
1698 if ((sc != null) && isDefaultContainer) {
1699 ForwardingMode mode = (ForwardingMode) sc.getProperty(ForwardingMode.name);
1700 service.modeChangeNotify(node, (mode == null) ? false : mode.isProactive());
1705 private void bulkUpdateService(IInventoryListener service) {
1706 Map<String, Property> propMap;
1707 UpdateType type = UpdateType.ADDED;
1709 for (Node node : getNodes()) {
1710 propMap = nodeProps.get(node);
1711 service.notifyNode(node, type, propMap);
1714 for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
1715 propMap = nodeConnectorProps.get(nodeConnector);
1716 service.notifyNodeConnector(nodeConnector, type, propMap);
1720 private void spanAwareNotify(ISpanAware service) {
1721 for (Node node : getNodes()) {
1722 for (SpanConfig conf : getSpanConfigList(node)) {
1723 service.spanUpdate(node, conf.getPortArrayList(), true);
1728 private void registerWithOSGIConsole() {
1729 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
1730 .getBundleContext();
1731 bundleContext.registerService(CommandProvider.class.getName(), this,
1736 public Boolean isNodeConnectorEnabled(NodeConnector nodeConnector) {
1737 if (nodeConnector == null) {
1741 Config config = (Config) getNodeConnectorProp(nodeConnector,
1742 Config.ConfigPropName);
1743 State state = (State) getNodeConnectorProp(nodeConnector,
1744 State.StatePropName);
1745 return ((config != null) && (config.getValue() == Config.ADMIN_UP)
1746 && (state != null) && (state.getValue() == State.EDGE_UP));
1750 public String getHelp() {
1751 StringBuffer help = new StringBuffer();
1752 help.append("---Switch Manager---\n");
1753 help.append("\t pns - Print connected nodes\n");
1754 help.append("\t pncs <node id> - Print node connectors for a given node\n");
1755 help.append("\t pencs <node id> - Print enabled node connectors for a given node\n");
1756 help.append("\t pdm <node id> - Print switch ports in device map\n");
1757 help.append("\t snt <node id> <tier> - Set node tier number\n");
1758 help.append("\t hostRefresh <on/off/?> - Enable/Disable/Query host refresh\n");
1759 help.append("\t hostRetry <count> - Set host retry count\n");
1760 return help.toString();
1763 public void _pns(CommandInterpreter ci) {
1764 ci.println(" Node Type MAC Name Tier");
1765 if (nodeProps == null) {
1768 Set<Node> nodeSet = nodeProps.keySet();
1769 if (nodeSet == null) {
1772 List<String> nodeArray = new ArrayList<String>();
1773 for (Node node : nodeSet) {
1774 nodeArray.add(node.toString());
1776 Collections.sort(nodeArray);
1777 for (String str: nodeArray) {
1778 Node node = Node.fromString(str);
1779 Description desc = ((Description) getNodeProp(node,
1780 Description.propertyName));
1781 Tier tier = ((Tier) getNodeProp(node, Tier.TierPropName));
1782 String nodeName = (desc == null) ? "" : desc.getValue();
1783 MacAddress mac = (MacAddress) getNodeProp(node,
1785 String macAddr = (mac == null) ? "" : HexEncode
1786 .bytesToHexStringFormat(mac.getMacAddress());
1787 int tierNum = (tier == null) ? 0 : tier.getValue();
1788 ci.println(node + " " + node.getType() + " " + macAddr
1789 + " " + nodeName + " " + tierNum);
1791 ci.println("Total number of Nodes: " + nodeSet.size());
1794 public void _pencs(CommandInterpreter ci) {
1795 String st = ci.nextArgument();
1797 ci.println("Please enter node id");
1801 Node node = Node.fromString(st);
1803 ci.println("Please enter node id");
1807 Set<NodeConnector> nodeConnectorSet = getUpNodeConnectors(node);
1808 if (nodeConnectorSet == null) {
1811 for (NodeConnector nodeConnector : nodeConnectorSet) {
1812 if (nodeConnector == null) {
1815 ci.println(nodeConnector);
1817 ci.println("Total number of NodeConnectors: " + nodeConnectorSet.size());
1820 public void _pncs(CommandInterpreter ci) {
1821 String st = ci.nextArgument();
1823 ci.println("Please enter node id");
1827 Node node = Node.fromString(st);
1829 ci.println("Please enter node id");
1833 ci.println(" NodeConnector BandWidth(Gbps) Admin State");
1834 Set<NodeConnector> nodeConnectorSet = getNodeConnectors(node);
1835 if (nodeConnectorSet == null) {
1838 for (NodeConnector nodeConnector : nodeConnectorSet) {
1839 if (nodeConnector == null) {
1842 Map<String, Property> propMap = getNodeConnectorProps(nodeConnector);
1843 Bandwidth bw = (Bandwidth) propMap.get(Bandwidth.BandwidthPropName);
1844 Config config = (Config) propMap.get(Config.ConfigPropName);
1845 State state = (State) propMap.get(State.StatePropName);
1846 String out = nodeConnector + " ";
1847 out += (bw != null) ? bw.getValue() / Math.pow(10, 9) : " ";
1849 out += (config != null) ? config.getValue() : " ";
1851 out += (state != null) ? state.getValue() : " ";
1854 ci.println("Total number of NodeConnectors: " + nodeConnectorSet.size());
1857 public void _pdm(CommandInterpreter ci) {
1858 String st = ci.nextArgument();
1860 ci.println("Please enter node id");
1864 Node node = Node.fromString(st);
1866 ci.println("Please enter node id");
1870 Switch sw = getSwitchByNode(node);
1872 ci.println(" NodeConnector Name");
1876 Set<NodeConnector> nodeConnectorSet = sw.getNodeConnectors();
1877 String nodeConnectorName;
1878 if (nodeConnectorSet != null && nodeConnectorSet.size() > 0) {
1879 for (NodeConnector nodeConnector : nodeConnectorSet) {
1880 Map<String, Property> propMap = getNodeConnectorProps(nodeConnector);
1881 nodeConnectorName = (propMap == null) ? null : ((Name) propMap
1882 .get(Name.NamePropName)).getValue();
1883 if (nodeConnectorName != null) {
1884 Node nd = nodeConnector.getNode();
1885 if (!nd.equals(node)) {
1886 log.debug("node not match {} {}", nd, node);
1888 Map<String, NodeConnector> map = nodeConnectorNames
1891 NodeConnector nc = map.get(nodeConnectorName);
1893 log.debug("no nodeConnector named {}",
1895 } else if (!nc.equals(nodeConnector)) {
1896 log.debug("nodeConnector not match {} {}", nc,
1902 ci.println(nodeConnector
1904 + ((nodeConnectorName == null) ? "" : nodeConnectorName)
1905 + "(" + nodeConnector.getID() + ")");
1907 ci.println("Total number of NodeConnectors: "
1908 + nodeConnectorSet.size());
1912 public void _snt(CommandInterpreter ci) {
1913 String st = ci.nextArgument();
1915 ci.println("Please enter node id");
1919 Node node = Node.fromString(st);
1921 ci.println("Please enter node id");
1925 st = ci.nextArgument();
1927 ci.println("Please enter tier number");
1930 Integer tid = Integer.decode(st);
1931 Tier tier = new Tier(tid);
1932 setNodeProp(node, tier);
1935 public void _hostRefresh(CommandInterpreter ci) {
1936 String mode = ci.nextArgument();
1938 ci.println("expecting on/off/?");
1941 if (mode.toLowerCase().equals("on")) {
1943 } else if (mode.toLowerCase().equals("off")) {
1944 hostRefresh = false;
1945 } else if (mode.equals("?")) {
1947 ci.println("host refresh is ON");
1949 ci.println("host refresh is OFF");
1952 ci.println("expecting on/off/?");
1957 public void _hostRetry(CommandInterpreter ci) {
1958 String retry = ci.nextArgument();
1959 if (retry == null) {
1960 ci.println("Please enter a valid number. Current retry count is "
1965 hostRetryCount = Integer.parseInt(retry);
1966 } catch (Exception e) {
1967 ci.println("Please enter a valid number");
1973 public byte[] getNodeMAC(Node node) {
1974 MacAddress mac = (MacAddress) this.getNodeProp(node,
1976 return (mac != null) ? mac.getMacAddress() : null;
1980 public boolean isSpecial(NodeConnector p) {
1981 if (p.getType().equals(NodeConnectorIDType.CONTROLLER)
1982 || p.getType().equals(NodeConnectorIDType.ALL)
1983 || p.getType().equals(NodeConnectorIDType.SWSTACK)
1984 || p.getType().equals(NodeConnectorIDType.HWPATH)) {
1991 * Add span configuration to local cache and notify clients
1993 private void addSpanPorts(Node node, List<NodeConnector> nodeConnectors) {
1994 List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
1996 for (NodeConnector nodeConnector : nodeConnectors) {
1997 if (!spanNodeConnectors.contains(nodeConnector)) {
1998 ncLists.add(nodeConnector);
2002 if (ncLists.size() > 0) {
2003 spanNodeConnectors.addAll(ncLists);
2004 notifySpanPortChange(node, ncLists, true);
2008 private void addSpanPorts(Node node) {
2009 for (SpanConfig conf : getSpanConfigList(node)) {
2010 addSpanPorts(node, conf.getPortArrayList());
2014 private void addSpanPort(NodeConnector nodeConnector) {
2015 // only add if span is configured on this nodeConnector
2016 for (SpanConfig conf : getSpanConfigList(nodeConnector.getNode())) {
2017 if (conf.getPortArrayList().contains(nodeConnector)) {
2018 List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
2019 ncLists.add(nodeConnector);
2020 addSpanPorts(nodeConnector.getNode(), ncLists);
2027 * Remove span configuration to local cache and notify clients
2029 private void removeSpanPorts(Node node, List<NodeConnector> nodeConnectors) {
2030 List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
2032 for (NodeConnector nodeConnector : nodeConnectors) {
2033 if (spanNodeConnectors.contains(nodeConnector)) {
2034 ncLists.add(nodeConnector);
2038 if (ncLists.size() > 0) {
2039 spanNodeConnectors.removeAll(ncLists);
2040 notifySpanPortChange(node, ncLists, false);
2044 private void removeSpanPorts(Node node) {
2045 for (SpanConfig conf : getSpanConfigList(node)) {
2046 addSpanPorts(node, conf.getPortArrayList());
2050 private void removeSpanPort(NodeConnector nodeConnector) {
2051 if (spanNodeConnectors.contains(nodeConnector)) {
2052 List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
2053 ncLists.add(nodeConnector);
2054 removeSpanPorts(nodeConnector.getNode(), ncLists);
2058 private void addNodeProps(Node node, Map<String, Property> propMap) {
2059 if (propMap == null) {
2060 propMap = new HashMap<String, Property>();
2062 nodeProps.put(node, propMap);
2066 public Status saveConfiguration() {
2067 return saveSwitchConfig();
2071 * Creates a Name/Tier/Bandwidth Property object based on given property
2072 * name and value. Other property types are not supported yet.
2075 * Name of the Property
2077 * Value of the Property
2078 * @return {@link org.opendaylight.controller.sal.core.Property}
2081 public Property createProperty(String propName, String propValue) {
2082 if (propName == null) {
2083 log.debug("propName is null");
2086 if (propValue == null) {
2087 log.debug("propValue is null");
2092 if (propName.equalsIgnoreCase(Description.propertyName)) {
2093 return new Description(propValue);
2094 } else if (propName.equalsIgnoreCase(Tier.TierPropName)) {
2095 int tier = Integer.parseInt(propValue);
2096 return new Tier(tier);
2097 } else if (propName.equalsIgnoreCase(Bandwidth.BandwidthPropName)) {
2098 long bw = Long.parseLong(propValue);
2099 return new Bandwidth(bw);
2100 } else if (propName.equalsIgnoreCase(ForwardingMode.name)) {
2101 int mode = Integer.parseInt(propValue);
2102 return new ForwardingMode(mode);
2104 log.debug("Not able to create {} property", propName);
2106 } catch (Exception e) {
2107 log.debug("createProperty caught exception {}", e.getMessage());
2114 public String getNodeDescription(Node node) {
2115 // Check first if user configured a name
2116 SwitchConfig config = getSwitchConfig(node.toString());
2117 if (config != null) {
2118 String configuredDesc = config.getNodeDescription();
2119 if (configuredDesc != null && !configuredDesc.isEmpty()) {
2120 return configuredDesc;
2124 // No name configured by user, get the node advertised name
2125 Description desc = (Description) getNodeProp(node,
2126 Description.propertyName);
2127 return (desc == null /* || desc.getValue().equalsIgnoreCase("none") */) ? ""