d32f98650b8b549ce8235fd3c14d22c55205ac56
[controller.git] / opendaylight / switchmanager / implementation / src / main / java / org / opendaylight / controller / switchmanager / internal / SwitchManagerImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.switchmanager.internal;
10
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;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ConcurrentMap;
30 import java.util.concurrent.CopyOnWriteArrayList;
31
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.Description;
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.utils.GlobalConstants;
56 import org.opendaylight.controller.sal.utils.HexEncode;
57 import org.opendaylight.controller.sal.utils.IObjectReader;
58 import org.opendaylight.controller.sal.utils.ObjectReader;
59 import org.opendaylight.controller.sal.utils.ObjectWriter;
60 import org.opendaylight.controller.sal.utils.ServiceHelper;
61 import org.opendaylight.controller.sal.utils.Status;
62 import org.opendaylight.controller.sal.utils.StatusCode;
63 import org.opendaylight.controller.switchmanager.IInventoryListener;
64 import org.opendaylight.controller.switchmanager.ISpanAware;
65 import org.opendaylight.controller.switchmanager.ISwitchManager;
66 import org.opendaylight.controller.switchmanager.ISwitchManagerAware;
67 import org.opendaylight.controller.switchmanager.SpanConfig;
68 import org.opendaylight.controller.switchmanager.Subnet;
69 import org.opendaylight.controller.switchmanager.SubnetConfig;
70 import org.opendaylight.controller.switchmanager.Switch;
71 import org.opendaylight.controller.switchmanager.SwitchConfig;
72 import org.osgi.framework.BundleContext;
73 import org.osgi.framework.FrameworkUtil;
74 import org.slf4j.Logger;
75 import org.slf4j.LoggerFactory;
76
77 /**
78  * The class describes SwitchManager which is the central repository of all the
79  * inventory data including nodes, node connectors, properties attached, Layer3
80  * configurations, Span configurations, node configurations, network device
81  * representations viewed by Controller Web applications. One SwitchManager
82  * instance per container of the network. All the node/nodeConnector properties
83  * are maintained in the default container only.
84  */
85 public class SwitchManagerImpl implements ISwitchManager,
86 IConfigurationContainerAware, IObjectReader,
87 ICacheUpdateAware<Long, String>, IListenInventoryUpdates,
88 CommandProvider {
89     private static Logger log = LoggerFactory
90             .getLogger(SwitchManagerImpl.class);
91     private static String ROOT = GlobalConstants.STARTUPHOME.toString();
92     private static final String SAVE = "Save";
93     private String subnetFileName = null, spanFileName = null,
94             switchConfigFileName = null;
95     private final List<NodeConnector> spanNodeConnectors = new CopyOnWriteArrayList<NodeConnector>();
96     private ConcurrentMap<InetAddress, Subnet> subnets; // set of Subnets keyed by the InetAddress
97     private ConcurrentMap<String, SubnetConfig> subnetsConfigList;
98     private ConcurrentMap<Integer, SpanConfig> spanConfigList;
99     private ConcurrentMap<String, SwitchConfig> nodeConfigList; // manually configured parameters for the node like name and tier
100     private ConcurrentMap<Long, String> configSaveEvent;
101     private ConcurrentMap<Node, Map<String, Property>> nodeProps; // properties are maintained in global container only
102     private ConcurrentMap<NodeConnector, Map<String, Property>> nodeConnectorProps; // properties are maintained in global container only
103     private ConcurrentMap<Node, Map<String, NodeConnector>> nodeConnectorNames;
104     private IInventoryService inventoryService;
105     private final Set<ISwitchManagerAware> switchManagerAware = Collections
106             .synchronizedSet(new HashSet<ISwitchManagerAware>());
107     private final Set<IInventoryListener> inventoryListeners = Collections
108             .synchronizedSet(new HashSet<IInventoryListener>());
109     private final Set<ISpanAware> spanAware = Collections
110             .synchronizedSet(new HashSet<ISpanAware>());
111     private byte[] MAC;
112     private static boolean hostRefresh = true;
113     private int hostRetryCount = 5;
114     private IClusterContainerServices clusterContainerService = null;
115     private String containerName = null;
116     private boolean isDefaultContainer = true;
117
118     public enum ReasonCode {
119         SUCCESS("Success"), FAILURE("Failure"), INVALID_CONF(
120                 "Invalid Configuration"), EXIST("Entry Already Exist"), CONFLICT(
121                         "Configuration Conflict with Existing Entry");
122
123         private final String name;
124
125         private ReasonCode(String name) {
126             this.name = name;
127         }
128
129         @Override
130         public String toString() {
131             return name;
132         }
133     }
134
135     public void notifySubnetChange(Subnet sub, boolean add) {
136         synchronized (switchManagerAware) {
137             for (Object subAware : switchManagerAware) {
138                 try {
139                     ((ISwitchManagerAware) subAware).subnetNotify(sub, add);
140                 } catch (Exception e) {
141                     log.error("Failed to notify Subnet change {}",
142                             e.getMessage());
143                 }
144             }
145         }
146     }
147
148     public void notifySpanPortChange(Node node, List<NodeConnector> ports,
149             boolean add) {
150         synchronized (spanAware) {
151             for (Object sa : spanAware) {
152                 try {
153                     ((ISpanAware) sa).spanUpdate(node, ports, add);
154                 } catch (Exception e) {
155                     log.error("Failed to notify Span Interface change {}",
156                             e.getMessage());
157                 }
158             }
159         }
160     }
161
162     private void notifyModeChange(Node node, boolean proactive) {
163         synchronized (switchManagerAware) {
164             for (ISwitchManagerAware service : switchManagerAware) {
165                 try {
166                     service.modeChangeNotify(node, proactive);
167                 } catch (Exception e) {
168                     log.error("Failed to notify Subnet change {}",
169                             e.getMessage());
170                 }
171             }
172         }
173     }
174
175     public void startUp() {
176         // Initialize configuration file names
177         subnetFileName = ROOT + "subnets_" + this.getContainerName() + ".conf";
178         spanFileName = ROOT + "spanPorts_" + this.getContainerName() + ".conf";
179         switchConfigFileName = ROOT + "switchConfig_" + this.getContainerName()
180                 + ".conf";
181
182         // Instantiate cluster synced variables
183         allocateCaches();
184         retrieveCaches();
185
186         /*
187          * Read startup and build database if we have not already gotten the
188          * configurations synced from another node
189          */
190         if (subnetsConfigList.isEmpty()) {
191             loadSubnetConfiguration();
192         }
193         if (spanConfigList.isEmpty()) {
194             loadSpanConfiguration();
195         }
196         if (nodeConfigList.isEmpty()) {
197             loadSwitchConfiguration();
198         }
199
200         MAC = getHardwareMAC();
201     }
202
203     public void shutDown() {
204     }
205
206     @SuppressWarnings("deprecation")
207     private void allocateCaches() {
208         if (this.clusterContainerService == null) {
209             log.warn("un-initialized clusterContainerService, can't create cache");
210             return;
211         }
212
213         try {
214             clusterContainerService.createCache(
215                     "switchmanager.subnetsConfigList",
216                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
217             clusterContainerService.createCache("switchmanager.spanConfigList",
218                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
219             clusterContainerService.createCache("switchmanager.nodeConfigList",
220                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
221             clusterContainerService.createCache("switchmanager.subnets",
222                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
223             clusterContainerService.createCache(
224                     "switchmanager.configSaveEvent",
225                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
226             clusterContainerService.createCache("switchmanager.nodeProps",
227                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
228             clusterContainerService.createCache(
229                     "switchmanager.nodeConnectorProps",
230                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
231             clusterContainerService.createCache(
232                     "switchmanager.nodeConnectorNames",
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");
238         }
239     }
240
241     @SuppressWarnings({ "unchecked", "deprecation" })
242     private void retrieveCaches() {
243         if (this.clusterContainerService == null) {
244             log.info("un-initialized clusterContainerService, can't create cache");
245             return;
246         }
247
248         subnetsConfigList = (ConcurrentMap<String, SubnetConfig>) clusterContainerService
249                 .getCache("switchmanager.subnetsConfigList");
250         if (subnetsConfigList == null) {
251             log.error("\nFailed to get cache for subnetsConfigList");
252         }
253
254         spanConfigList = (ConcurrentMap<Integer, SpanConfig>) clusterContainerService
255                 .getCache("switchmanager.spanConfigList");
256         if (spanConfigList == null) {
257             log.error("\nFailed to get cache for spanConfigList");
258         }
259
260         nodeConfigList = (ConcurrentMap<String, SwitchConfig>) clusterContainerService
261                 .getCache("switchmanager.nodeConfigList");
262         if (nodeConfigList == null) {
263             log.error("\nFailed to get cache for nodeConfigList");
264         }
265
266         subnets = (ConcurrentMap<InetAddress, Subnet>) clusterContainerService
267                 .getCache("switchmanager.subnets");
268         if (subnets == null) {
269             log.error("\nFailed to get cache for subnets");
270         }
271
272         configSaveEvent = (ConcurrentMap<Long, String>) clusterContainerService
273                 .getCache("switchmanager.configSaveEvent");
274         if (configSaveEvent == null) {
275             log.error("\nFailed to get cache for configSaveEvent");
276         }
277
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");
282         }
283
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");
288         }
289
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");
294         }
295     }
296
297     void nonClusterObjectCreate() {
298         subnetsConfigList = new ConcurrentHashMap<String, SubnetConfig>();
299         spanConfigList = new ConcurrentHashMap<Integer, SpanConfig>();
300         nodeConfigList = new ConcurrentHashMap<String, SwitchConfig>();
301         subnets = new ConcurrentHashMap<InetAddress, Subnet>();
302         configSaveEvent = new ConcurrentHashMap<Long, String>();
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     }
307
308     @SuppressWarnings("deprecation")
309     private void destroyCaches(String container) {
310         if (this.clusterContainerService == null) {
311             log.info("un-initialized clusterContainerService, can't create cache");
312             return;
313         }
314
315         clusterContainerService.destroyCache("switchmanager.subnetsConfigList");
316         clusterContainerService.destroyCache("switchmanager.spanConfigList");
317         clusterContainerService.destroyCache("switchmanager.nodeConfigList");
318         clusterContainerService.destroyCache("switchmanager.subnets");
319         clusterContainerService.destroyCache("switchmanager.configSaveEvent");
320         clusterContainerService.destroyCache("switchmanager.nodeProps");
321         clusterContainerService
322         .destroyCache("switchmanager.nodeConnectorProps");
323         clusterContainerService
324         .destroyCache("switchmanager.nodeConnectorNames");
325         nonClusterObjectCreate();
326     }
327
328     @Override
329     public List<SubnetConfig> getSubnetsConfigList() {
330         return new ArrayList<SubnetConfig>(subnetsConfigList.values());
331     }
332
333     @Override
334     public SubnetConfig getSubnetConfig(String subnet) {
335         return subnetsConfigList.get(subnet);
336     }
337
338     private List<SpanConfig> getSpanConfigList(Node node) {
339         List<SpanConfig> confList = new ArrayList<SpanConfig>();
340         String nodeId = node.toString();
341         for (SpanConfig conf : spanConfigList.values()) {
342             if (conf.matchNode(nodeId)) {
343                 confList.add(conf);
344             }
345         }
346         return confList;
347     }
348
349     public List<SwitchConfig> getNodeConfigList() {
350         return new ArrayList<SwitchConfig>(nodeConfigList.values());
351     }
352
353     @Override
354     public SwitchConfig getSwitchConfig(String switchId) {
355         return nodeConfigList.get(switchId);
356     }
357
358     public Switch getSwitchByNode(Node node) {
359         Switch sw = new Switch(node);
360         sw.setNode(node);
361         MacAddress mac = (MacAddress) this.getNodeProp(node,
362                 MacAddress.name);
363         if (mac != null) {
364             sw.setDataLayerAddress(mac.getMacAddress());
365         }
366         Set<NodeConnector> ncSet = getPhysicalNodeConnectors(node);
367         sw.setNodeConnectors(ncSet);
368
369         List<NodeConnector> ncList = new ArrayList<NodeConnector>();
370         for (NodeConnector nodeConnector : ncSet) {
371             if (spanNodeConnectors.contains(nodeConnector)) {
372                 ncList.add(nodeConnector);
373             }
374         }
375         sw.addSpanPorts(ncList);
376
377         return sw;
378     }
379
380     @Override
381     public List<Switch> getNetworkDevices() {
382         Set<Node> nodeSet = getNodes();
383         List<Switch> swList = new ArrayList<Switch>();
384         if (nodeSet != null) {
385             for (Node node : nodeSet) {
386                 swList.add(getSwitchByNode(node));
387             }
388         }
389
390         return swList;
391     }
392
393     private void updateConfig(SubnetConfig conf, boolean add) {
394         if (add) {
395             subnetsConfigList.put(conf.getName(), conf);
396         } else {
397             subnetsConfigList.remove(conf.getName());
398         }
399     }
400
401     private void updateDatabase(SubnetConfig conf, boolean add) {
402         Subnet subnet = subnets.get(conf.getIPnum());
403         if (add) {
404             if (subnet == null) {
405                 subnet = new Subnet(conf);
406             }
407             // In case of API3 call we may receive the ports along with the
408             // subnet creation
409             if (!conf.isGlobal()) {
410                 Set<NodeConnector> sp = conf.getSubnetNodeConnectors();
411                 subnet.addNodeConnectors(sp);
412             }
413             subnets.put(conf.getIPnum(), subnet);
414         } else { // This is the deletion of the whole subnet
415             if (subnet == null) {
416                 return;
417             }
418             subnets.remove(conf.getIPnum());
419         }
420     }
421
422     private Status semanticCheck(SubnetConfig conf) {
423         Subnet newSubnet = new Subnet(conf);
424         Set<InetAddress> IPs = subnets.keySet();
425         if (IPs == null) {
426             return new Status(StatusCode.SUCCESS, null);
427         }
428         for (InetAddress i : IPs) {
429             Subnet existingSubnet = subnets.get(i);
430             if ((existingSubnet != null)
431                     && !existingSubnet.isMutualExclusive(newSubnet)) {
432                 return new Status(StatusCode.CONFLICT, null);
433             }
434         }
435         return new Status(StatusCode.SUCCESS, null);
436     }
437
438     private Status addRemoveSubnet(SubnetConfig conf, boolean add) {
439         // Valid config check
440         if (!conf.isValidConfig()) {
441             String msg = "Invalid Subnet configuration";
442             log.warn(msg);
443             return new Status(StatusCode.BADREQUEST, msg);
444         }
445
446         if (add) {
447             // Presence check
448             if (subnetsConfigList.containsKey(conf.getName())) {
449                 return new Status(StatusCode.CONFLICT,
450                         "Same subnet config already exists");
451             }
452             // Semantyc check
453             Status rc = semanticCheck(conf);
454             if (!rc.isSuccess()) {
455                 return rc;
456             }
457         }
458         // Update Configuration
459         updateConfig(conf, add);
460
461         // Update Database
462         updateDatabase(conf, add);
463
464         return new Status(StatusCode.SUCCESS, null);
465     }
466
467     /**
468      * Adds Subnet configured in GUI or API3
469      */
470     @Override
471     public Status addSubnet(SubnetConfig conf) {
472         return this.addRemoveSubnet(conf, true);
473     }
474
475     @Override
476     public Status removeSubnet(SubnetConfig conf) {
477         return this.addRemoveSubnet(conf, false);
478     }
479
480     @Override
481     public Status removeSubnet(String name) {
482         SubnetConfig conf = subnetsConfigList.get(name);
483         if (conf == null) {
484             return new Status(StatusCode.SUCCESS, "Subnet not present");
485         }
486         return this.addRemoveSubnet(conf, false);
487     }
488
489     @Override
490     public Status addPortsToSubnet(String name, String switchPorts) {
491         // Update Configuration
492         SubnetConfig conf = subnetsConfigList.get(name);
493         if (conf == null) {
494             return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
495         }
496         if (!conf.isValidSwitchPort(switchPorts)) {
497             return new Status(StatusCode.BADREQUEST, "Invalid switchports");
498         }
499
500         conf.addNodeConnectors(switchPorts);
501         subnetsConfigList.put(name, conf);
502
503         // Update Database
504         Subnet sub = subnets.get(conf.getIPnum());
505         Set<NodeConnector> sp = conf.getNodeConnectors(switchPorts);
506         sub.addNodeConnectors(sp);
507         subnets.put(conf.getIPnum(), sub);
508         return new Status(StatusCode.SUCCESS, null);
509     }
510
511     @Override
512     public Status removePortsFromSubnet(String name, String switchPorts) {
513         // Update Configuration
514         SubnetConfig conf = subnetsConfigList.get(name);
515         if (conf == null) {
516             return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
517         }
518         conf.removeNodeConnectors(switchPorts);
519         subnetsConfigList.put(name, conf);
520
521         // Update Database
522         Subnet sub = subnets.get(conf.getIPnum());
523         Set<NodeConnector> sp = conf.getNodeConnectors(switchPorts);
524         sub.deleteNodeConnectors(sp);
525         subnets.put(conf.getIPnum(), sub);
526         return new Status(StatusCode.SUCCESS, null);
527     }
528
529     public String getContainerName() {
530         if (containerName == null) {
531             return GlobalConstants.DEFAULT.toString();
532         }
533         return containerName;
534     }
535
536     @Override
537     public Subnet getSubnetByNetworkAddress(InetAddress networkAddress) {
538         Subnet sub;
539         Set<InetAddress> indices = subnets.keySet();
540         for (InetAddress i : indices) {
541             sub = subnets.get(i);
542             if (sub.isSubnetOf(networkAddress)) {
543                 return sub;
544             }
545         }
546         return null;
547     }
548
549     @Override
550     public Object readObject(ObjectInputStream ois)
551             throws FileNotFoundException, IOException, ClassNotFoundException {
552         // Perform the class deserialization locally, from inside the package
553         // where the class is defined
554         return ois.readObject();
555     }
556
557     @SuppressWarnings("unchecked")
558     private void loadSubnetConfiguration() {
559         ObjectReader objReader = new ObjectReader();
560         ConcurrentMap<String, SubnetConfig> confList = (ConcurrentMap<String, SubnetConfig>) objReader
561                 .read(this, subnetFileName);
562
563         if (confList == null) {
564             return;
565         }
566
567         for (SubnetConfig conf : confList.values()) {
568             addSubnet(conf);
569         }
570     }
571
572     @SuppressWarnings("unchecked")
573     private void loadSpanConfiguration() {
574         ObjectReader objReader = new ObjectReader();
575         ConcurrentMap<Integer, SpanConfig> confList = (ConcurrentMap<Integer, SpanConfig>) objReader
576                 .read(this, spanFileName);
577
578         if (confList == null) {
579             return;
580         }
581
582         for (SpanConfig conf : confList.values()) {
583             addSpanConfig(conf);
584         }
585     }
586
587     @SuppressWarnings("unchecked")
588     private void loadSwitchConfiguration() {
589         ObjectReader objReader = new ObjectReader();
590         ConcurrentMap<String, SwitchConfig> confList = (ConcurrentMap<String, SwitchConfig>) objReader
591                 .read(this, switchConfigFileName);
592
593         if (confList == null) {
594             return;
595         }
596
597         for (SwitchConfig conf : confList.values()) {
598             updateSwitchConfig(conf);
599         }
600     }
601
602     @Override
603     public void updateSwitchConfig(SwitchConfig cfgObject) {
604         // update default container only
605         if (!isDefaultContainer) {
606             return;
607         }
608
609         boolean modeChange = false;
610
611         SwitchConfig sc = nodeConfigList.get(cfgObject.getNodeId());
612         if ((sc == null) || !cfgObject.getMode().equals(sc.getMode())) {
613             modeChange = true;
614         }
615
616         nodeConfigList.put(cfgObject.getNodeId(), cfgObject);
617         try {
618             String nodeId = cfgObject.getNodeId();
619             Node node = Node.fromString(nodeId);
620             Map<String, Property> propMap;
621             if (nodeProps.get(node) != null) {
622                 propMap = nodeProps.get(node);
623             } else {
624                 propMap = new HashMap<String, Property>();
625             }
626             Property desc = new Description(cfgObject.getNodeDescription());
627             propMap.put(desc.getName(), desc);
628             Property tier = new Tier(Integer.parseInt(cfgObject.getTier()));
629             propMap.put(tier.getName(), tier);
630             addNodeProps(node, propMap);
631
632             log.info("Set Node {}'s Mode to {}", nodeId,
633                     cfgObject.getMode());
634
635             if (modeChange) {
636                 notifyModeChange(node, cfgObject.isProactive());
637             }
638         } catch (Exception e) {
639             log.debug("updateSwitchConfig: {}", e.getMessage());
640         }
641     }
642
643     @Override
644     public Status saveSwitchConfig() {
645         // Publish the save config event to the cluster nodes
646         configSaveEvent.put(new Date().getTime(), SAVE);
647         return saveSwitchConfigInternal();
648     }
649
650     public Status saveSwitchConfigInternal() {
651         Status retS = null, retP = null;
652         ObjectWriter objWriter = new ObjectWriter();
653
654         retS = objWriter.write(new ConcurrentHashMap<String, SubnetConfig>(
655                 subnetsConfigList), subnetFileName);
656         retP = objWriter.write(new ConcurrentHashMap<Integer, SpanConfig>(
657                 spanConfigList), spanFileName);
658         retS = objWriter.write(new ConcurrentHashMap<String, SwitchConfig>(
659                 nodeConfigList), switchConfigFileName);
660
661         if (retS.equals(retP)) {
662             if (retS.isSuccess()) {
663                 return retS;
664             } else {
665                 return new Status(StatusCode.INTERNALERROR, "Save failed");
666             }
667         } else {
668             return new Status(StatusCode.INTERNALERROR, "Partial save failure");
669         }
670     }
671
672     @Override
673     public List<SpanConfig> getSpanConfigList() {
674         return new ArrayList<SpanConfig>(spanConfigList.values());
675     }
676
677     @Override
678     public Status addSpanConfig(SpanConfig conf) {
679         // Valid config check
680         if (!conf.isValidConfig()) {
681             String msg = "Invalid Span configuration";
682             log.warn(msg);
683             return new Status(StatusCode.BADREQUEST, msg);
684         }
685
686         // Presence check
687         if (spanConfigList.containsKey(conf.hashCode())) {
688             return new Status(StatusCode.CONFLICT, "Same span config exists");
689         }
690
691         // Update database and notify clients
692         addSpanPorts(conf.getNode(), conf.getPortArrayList());
693
694         // Update configuration
695         spanConfigList.put(conf.hashCode(), conf);
696
697         return new Status(StatusCode.SUCCESS, null);
698     }
699
700     @Override
701     public Status removeSpanConfig(SpanConfig conf) {
702         removeSpanPorts(conf.getNode(), conf.getPortArrayList());
703
704         // Update configuration
705         spanConfigList.remove(conf.hashCode());
706
707         return new Status(StatusCode.SUCCESS, null);
708     }
709
710     @Override
711     public List<NodeConnector> getSpanPorts(Node node) {
712         List<NodeConnector> ncList = new ArrayList<NodeConnector>();
713
714         for (NodeConnector nodeConnector : spanNodeConnectors) {
715             if (nodeConnector.getNode().equals(node)) {
716                 ncList.add(nodeConnector);
717             }
718         }
719         return ncList;
720     }
721
722     @Override
723     public void entryCreated(Long key, String cacheName, boolean local) {
724     }
725
726     @Override
727     public void entryUpdated(Long key, String new_value, String cacheName,
728             boolean originLocal) {
729         saveSwitchConfigInternal();
730     }
731
732     @Override
733     public void entryDeleted(Long key, String cacheName, boolean originLocal) {
734     }
735
736     private void addNode(Node node, Set<Property> props) {
737         log.trace("{} added, props: {}", node, props);
738         if (nodeProps == null) {
739             return;
740         }
741
742         Map<String, Property> propMap;
743         if (nodeProps.get(node) != null) {
744             propMap = nodeProps.get(node);
745         } else {
746             propMap = new HashMap<String, Property>();
747         }
748
749         // copy node properties from plugin
750         if (props != null) {
751             for (Property prop : props) {
752                 propMap.put(prop.getName(), prop);
753             }
754         }
755
756         // copy node properties from config
757         boolean proactiveForwarding = false;
758         if (nodeConfigList != null) {
759             String nodeId = node.toString();
760             for (SwitchConfig conf : nodeConfigList.values()) {
761                 if (conf.getNodeId().equals(nodeId)) {
762                     Property description = new Description(
763                             conf.getNodeDescription());
764                     propMap.put(description.getName(), description);
765                     Property tier = new Tier(Integer.parseInt(conf.getTier()));
766                     propMap.put(tier.getName(), tier);
767                     proactiveForwarding = conf.isProactive();
768                     break;
769                 }
770             }
771         }
772         addNodeProps(node, propMap);
773
774         // check if span ports are configed
775         addSpanPorts(node);
776
777         // notify node listeners
778         notifyNode(node, UpdateType.ADDED, propMap);
779
780         // notify proactive mode forwarding
781         if (proactiveForwarding) {
782             notifyModeChange(node, true);
783         }
784     }
785
786     private void removeNode(Node node) {
787         log.trace("{} removed", node);
788         if (nodeProps == null) {
789             return;
790         }
791         nodeProps.remove(node);
792
793         // check if span ports need to be cleaned up
794         removeSpanPorts(node);
795
796         /* notify node listeners */
797         notifyNode(node, UpdateType.REMOVED, null);
798     }
799
800     private void updateNode(Node node, Set<Property> props) {
801         log.trace("{} updated, props: {}", node, props);
802         if (nodeProps == null || !nodeProps.containsKey(node) ||
803                 props == null || props.isEmpty()) {
804             return;
805         }
806
807         Map<String, Property> propMap;
808         if (nodeProps.get(node) != null) {
809             propMap = nodeProps.get(node);
810         } else {
811             propMap = new HashMap<String, Property>();
812         }
813
814         // copy node properties from plugin
815         if (props != null) {
816             for (Property prop : props) {
817                 propMap.put(prop.getName(), prop);
818             }
819         }
820         addNodeProps(node, propMap);
821
822         /* notify node listeners */
823         notifyNode(node, UpdateType.CHANGED, propMap);
824     }
825
826     @Override
827     public void updateNode(Node node, UpdateType type, Set<Property> props) {
828         log.debug("updateNode: {} type {} props {} for container {}",
829                 new Object[] { node, type, props, containerName });
830         switch (type) {
831         case ADDED:
832             addNode(node, props);
833             break;
834         case CHANGED:
835             updateNode(node, props);
836             break;
837         case REMOVED:
838             removeNode(node);
839             break;
840         default:
841             break;
842         }
843     }
844
845     @Override
846     public void updateNodeConnector(NodeConnector nodeConnector,
847             UpdateType type, Set<Property> props) {
848         Node node = nodeConnector.getNode();
849         Map<String, Property> propMap = new HashMap<String, Property>();
850
851         log.debug("updateNodeConnector: {} type {} props {} for container {}",
852                 new Object[] { nodeConnector, type, props, containerName });
853
854         if (nodeConnectorProps == null) {
855             return;
856         }
857
858         switch (type) {
859         case ADDED:
860         case CHANGED:
861             if (props != null) {
862                 for (Property prop : props) {
863                     addNodeConnectorProp(nodeConnector, prop);
864                     propMap.put(prop.getName(), prop);
865                 }
866             } else {
867                 addNodeConnectorProp(nodeConnector, null);
868                 addNodeProps(node, null);
869             }
870
871             addSpanPort(nodeConnector);
872             break;
873         case REMOVED:
874             removeNodeConnectorAllProps(nodeConnector);
875             removeNodeProps(node);
876
877             // clean up span config
878             removeSpanPort(nodeConnector);
879             break;
880         default:
881             break;
882         }
883
884         notifyNodeConnector(nodeConnector, type, propMap);
885     }
886
887     @Override
888     public Set<Node> getNodes() {
889         return (nodeProps != null) ? new HashSet<Node>(nodeProps.keySet())
890                 : null;
891     }
892
893     /*
894      * Returns a copy of a list of properties for a given node
895      *
896      * (non-Javadoc)
897      *
898      * @see
899      * org.opendaylight.controller.switchmanager.ISwitchManager#getNodeProps
900      * (org.opendaylight.controller.sal.core.Node)
901      */
902     @Override
903     public Map<String, Property> getNodeProps(Node node) {
904         if (isDefaultContainer) {
905             Map<String, Property> rv = null;
906             if (this.nodeProps != null) {
907                 rv = this.nodeProps.get(node);
908                 if (rv != null) {
909                     /* make a copy of it */
910                     rv = new HashMap<String, Property>(rv);
911                 }
912             }
913             return rv;
914         } else {
915             // get it from default container
916             ISwitchManager defaultSwitchManager = (ISwitchManager) ServiceHelper
917                     .getInstance(ISwitchManager.class,
918                             GlobalConstants.DEFAULT.toString(), this);
919             return defaultSwitchManager.getNodeProps(node);
920         }
921     }
922
923     @Override
924     public Property getNodeProp(Node node, String propName) {
925         Map<String, Property> propMap = getNodeProps(node);
926         return (propMap != null) ? propMap.get(propName) : null;
927     }
928
929     @Override
930     public void setNodeProp(Node node, Property prop) {
931         /* Get a copy of the property map */
932         Map<String, Property> propMap = getNodeProps(node);
933         if (propMap == null) {
934             return;
935         }
936
937         propMap.put(prop.getName(), prop);
938         this.nodeProps.put(node, propMap);
939     }
940
941     @Override
942     public Status removeNodeProp(Node node, String propName) {
943         Map<String, Property> propMap = getNodeProps(node);
944         if (propMap != null) {
945             propMap.remove(propName);
946             this.nodeProps.put(node, propMap);
947         }
948         return new Status(StatusCode.SUCCESS, null);
949     }
950
951     @Override
952     public Status removeNodeAllProps(Node node) {
953         this.nodeProps.remove(node);
954         return new Status(StatusCode.SUCCESS, null);
955     }
956
957     @Override
958     public Set<NodeConnector> getUpNodeConnectors(Node node) {
959         if (nodeConnectorProps == null) {
960             return null;
961         }
962
963         Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
964         for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
965             if (!nodeConnector.getNode().equals(node)) {
966                 continue;
967             }
968             if (isNodeConnectorEnabled(nodeConnector)) {
969                 nodeConnectorSet.add(nodeConnector);
970             }
971         }
972
973         return nodeConnectorSet;
974     }
975
976     @Override
977     public Set<NodeConnector> getNodeConnectors(Node node) {
978         if (nodeConnectorProps == null) {
979             return null;
980         }
981
982         Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
983         for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
984             if (!nodeConnector.getNode().equals(node)) {
985                 continue;
986             }
987             nodeConnectorSet.add(nodeConnector);
988         }
989
990         return nodeConnectorSet;
991     }
992
993     @Override
994     public Set<NodeConnector> getPhysicalNodeConnectors(Node node) {
995         if (nodeConnectorProps == null) {
996             return null;
997         }
998
999         Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
1000         for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
1001             if (!nodeConnector.getNode().equals(node)
1002                     || isSpecial(nodeConnector)) {
1003                 continue;
1004             }
1005             nodeConnectorSet.add(nodeConnector);
1006         }
1007
1008         return nodeConnectorSet;
1009     }
1010
1011     @Override
1012     public Map<String, Property> getNodeConnectorProps(
1013             NodeConnector nodeConnector) {
1014         if (isDefaultContainer) {
1015             Map<String, Property> rv = null;
1016             if (this.nodeConnectorProps != null) {
1017                 rv = this.nodeConnectorProps.get(nodeConnector);
1018                 if (rv != null) {
1019                     rv = new HashMap<String, Property>(rv);
1020                 }
1021             }
1022             return rv;
1023         } else {
1024             // get it from default container
1025             ISwitchManager defaultSwitchManager = (ISwitchManager) ServiceHelper
1026                     .getInstance(ISwitchManager.class,
1027                             GlobalConstants.DEFAULT.toString(), this);
1028             return defaultSwitchManager.getNodeConnectorProps(nodeConnector);
1029         }
1030     }
1031
1032     @Override
1033     public Property getNodeConnectorProp(NodeConnector nodeConnector,
1034             String propName) {
1035         Map<String, Property> propMap = getNodeConnectorProps(nodeConnector);
1036         return (propMap != null) ? propMap.get(propName) : null;
1037     }
1038
1039     private byte[] getHardwareMAC() {
1040         Enumeration<NetworkInterface> nis;
1041         try {
1042             nis = NetworkInterface.getNetworkInterfaces();
1043         } catch (SocketException e1) {
1044             log.error("",e1);
1045             return null;
1046         }
1047         byte[] MAC = null;
1048         for (; nis.hasMoreElements();) {
1049             NetworkInterface ni = nis.nextElement();
1050             try {
1051                 MAC = ni.getHardwareAddress();
1052             } catch (SocketException e) {
1053                 log.error("",e);
1054             }
1055             if (MAC != null) {
1056                 return MAC;
1057             }
1058         }
1059         return null;
1060     }
1061
1062     @Override
1063     public byte[] getControllerMAC() {
1064         return MAC;
1065     }
1066
1067     @Override
1068     public boolean isHostRefreshEnabled() {
1069         return hostRefresh;
1070     }
1071
1072     @Override
1073     public int getHostRetryCount() {
1074         return hostRetryCount;
1075     }
1076
1077     @Override
1078     public NodeConnector getNodeConnector(Node node, String nodeConnectorName) {
1079         if (nodeConnectorNames == null) {
1080             return null;
1081         }
1082
1083         Map<String, NodeConnector> map = nodeConnectorNames.get(node);
1084         if (map == null) {
1085             return null;
1086         }
1087
1088         return map.get(nodeConnectorName);
1089     }
1090
1091     /**
1092      * Adds a node connector and its property if any
1093      *
1094      * @param nodeConnector
1095      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
1096      * @param propName
1097      *            name of {@link org.opendaylight.controller.sal.core.Property}
1098      * @return success or failed reason
1099      */
1100     @Override
1101     public Status addNodeConnectorProp(NodeConnector nodeConnector,
1102             Property prop) {
1103         Map<String, Property> propMap = getNodeConnectorProps(nodeConnector);
1104
1105         if (propMap == null) {
1106             propMap = new HashMap<String, Property>();
1107         }
1108
1109         // Just add the nodeConnector if prop is not available (in a non-default
1110         // container)
1111         if (prop == null) {
1112             nodeConnectorProps.put(nodeConnector, propMap);
1113             return new Status(StatusCode.SUCCESS, null);
1114         }
1115
1116         propMap.put(prop.getName(), prop);
1117         nodeConnectorProps.put(nodeConnector, propMap);
1118
1119         if (prop.getName().equals(Name.NamePropName)) {
1120             if (nodeConnectorNames != null) {
1121                 Node node = nodeConnector.getNode();
1122                 Map<String, NodeConnector> map = nodeConnectorNames.get(node);
1123                 if (map == null) {
1124                     map = new HashMap<String, NodeConnector>();
1125                 }
1126
1127                 map.put(((Name) prop).getValue(), nodeConnector);
1128                 nodeConnectorNames.put(node, map);
1129             }
1130         }
1131
1132         return new Status(StatusCode.SUCCESS, null);
1133     }
1134
1135     /**
1136      * Removes one property of a node connector
1137      *
1138      * @param nodeConnector
1139      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
1140      * @param propName
1141      *            name of {@link org.opendaylight.controller.sal.core.Property}
1142      * @return success or failed reason
1143      */
1144     @Override
1145     public Status removeNodeConnectorProp(NodeConnector nodeConnector,
1146             String propName) {
1147         Map<String, Property> propMap = getNodeConnectorProps(nodeConnector);
1148
1149         if (propMap == null) {
1150             /* Nothing to remove */
1151             return new Status(StatusCode.SUCCESS, null);
1152         }
1153
1154         propMap.remove(propName);
1155         nodeConnectorProps.put(nodeConnector, propMap);
1156
1157         if (nodeConnectorNames != null) {
1158             Name name = ((Name) getNodeConnectorProp(nodeConnector,
1159                     Name.NamePropName));
1160             if (name != null) {
1161                 Node node = nodeConnector.getNode();
1162                 Map<String, NodeConnector> map = nodeConnectorNames.get(node);
1163                 if (map != null) {
1164                     map.remove(name.getValue());
1165                     nodeConnectorNames.put(node, map);
1166                 }
1167             }
1168         }
1169
1170         return new Status(StatusCode.SUCCESS, null);
1171     }
1172
1173     /**
1174      * Removes all the properties of a node connector
1175      *
1176      * @param nodeConnector
1177      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
1178      * @return success or failed reason
1179      */
1180     @Override
1181     public Status removeNodeConnectorAllProps(NodeConnector nodeConnector) {
1182         if (nodeConnectorNames != null) {
1183             Name name = ((Name) getNodeConnectorProp(nodeConnector,
1184                     Name.NamePropName));
1185             if (name != null) {
1186                 Node node = nodeConnector.getNode();
1187                 Map<String, NodeConnector> map = nodeConnectorNames.get(node);
1188                 if (map != null) {
1189                     map.remove(name.getValue());
1190                     nodeConnectorNames.put(node, map);
1191                 }
1192             }
1193         }
1194         nodeConnectorProps.remove(nodeConnector);
1195
1196         return new Status(StatusCode.SUCCESS, null);
1197     }
1198
1199     /**
1200      * Function called by the dependency manager when all the required
1201      * dependencies are satisfied
1202      *
1203      */
1204     void init(Component c) {
1205         Dictionary<?, ?> props = c.getServiceProperties();
1206         if (props != null) {
1207             this.containerName = (String) props.get("containerName");
1208             log.trace("Running containerName: {}", this.containerName);
1209         } else {
1210             // In the Global instance case the containerName is empty
1211             this.containerName = "";
1212         }
1213         isDefaultContainer = containerName.equals(GlobalConstants.DEFAULT
1214                 .toString());
1215
1216         startUp();
1217     }
1218
1219     /**
1220      * Function called by the dependency manager when at least one dependency
1221      * become unsatisfied or when the component is shutting down because for
1222      * example bundle is being stopped.
1223      *
1224      */
1225     void destroy() {
1226         shutDown();
1227     }
1228
1229     /**
1230      * Function called by dependency manager after "init ()" is called and after
1231      * the services provided by the class are registered in the service registry
1232      *
1233      */
1234     void start() {
1235         // OSGI console
1236         registerWithOSGIConsole();
1237     }
1238
1239     /**
1240      * Function called after registered the service in OSGi service registry.
1241      */
1242     void started() {
1243         // solicit for existing inventories
1244         getInventories();
1245     }
1246
1247     /**
1248      * Function called by the dependency manager before the services exported by
1249      * the component are unregistered, this will be followed by a "destroy ()"
1250      * calls
1251      *
1252      */
1253     void stop() {
1254     }
1255
1256     public void setInventoryService(IInventoryService service) {
1257         log.trace("Got inventory service set request {}", service);
1258         this.inventoryService = service;
1259
1260         // solicit for existing inventories
1261         getInventories();
1262     }
1263
1264     public void unsetInventoryService(IInventoryService service) {
1265         log.trace("Got a service UNset request");
1266         this.inventoryService = null;
1267
1268         // clear existing inventories
1269         clearInventories();
1270     }
1271
1272     public void setSwitchManagerAware(ISwitchManagerAware service) {
1273         log.trace("Got inventory service set request {}", service);
1274         if (this.switchManagerAware != null) {
1275             this.switchManagerAware.add(service);
1276         }
1277
1278         // bulk update for newly joined
1279         switchManagerAwareNotify(service);
1280     }
1281
1282     public void unsetSwitchManagerAware(ISwitchManagerAware service) {
1283         log.trace("Got a service UNset request");
1284         if (this.switchManagerAware != null) {
1285             this.switchManagerAware.remove(service);
1286         }
1287     }
1288
1289     public void setInventoryListener(IInventoryListener service) {
1290         log.trace("Got inventory listener set request {}", service);
1291         if (this.inventoryListeners != null) {
1292             this.inventoryListeners.add(service);
1293         }
1294
1295         // bulk update for newly joined
1296         bulkUpdateService(service);
1297     }
1298
1299     public void unsetInventoryListener(IInventoryListener service) {
1300         log.trace("Got a service UNset request");
1301         if (this.inventoryListeners != null) {
1302             this.inventoryListeners.remove(service);
1303         }
1304     }
1305
1306     public void setSpanAware(ISpanAware service) {
1307         log.trace("Got SpanAware set request {}", service);
1308         if (this.spanAware != null) {
1309             this.spanAware.add(service);
1310         }
1311
1312         // bulk update for newly joined
1313         spanAwareNotify(service);
1314     }
1315
1316     public void unsetSpanAware(ISpanAware service) {
1317         log.trace("Got a service UNset request");
1318         if (this.spanAware != null) {
1319             this.spanAware.remove(service);
1320         }
1321     }
1322
1323     void setClusterContainerService(IClusterContainerServices s) {
1324         log.trace("Cluster Service set");
1325         this.clusterContainerService = s;
1326     }
1327
1328     void unsetClusterContainerService(IClusterContainerServices s) {
1329         if (this.clusterContainerService == s) {
1330             log.trace("Cluster Service removed!");
1331             this.clusterContainerService = null;
1332         }
1333     }
1334
1335     private void getInventories() {
1336         if (inventoryService == null) {
1337             log.trace("inventory service not avaiable");
1338             return;
1339         }
1340
1341         Map<Node, Map<String, Property>> nodeProp = this.inventoryService.getNodeProps();
1342         for(Map.Entry<Node, Map<String, Property>> entry : nodeProp.entrySet()) {
1343             Node node = entry.getKey();
1344             log.debug("getInventories: {} added for container {}",
1345                     new Object[] { node, containerName });
1346             Map<String, Property> propMap = entry.getValue();
1347             Set<Property> props = new HashSet<Property>();
1348             for(Property property : propMap.values()) {
1349                 props.add(property);
1350             }
1351             addNode(node, props);
1352         }
1353
1354         Map<NodeConnector, Map<String, Property>> nodeConnectorProp = this.inventoryService.getNodeConnectorProps();
1355         for(Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProp.entrySet()) {
1356             Map<String, Property> propMap = entry.getValue();
1357             for(Property property : propMap.values()) {
1358                 addNodeConnectorProp(entry.getKey(), property);
1359             }
1360         }
1361     }
1362
1363     private void clearInventories() {
1364         nodeProps.clear();
1365         nodeConnectorProps.clear();
1366         nodeConnectorNames.clear();
1367         spanNodeConnectors.clear();
1368     }
1369
1370     private void notifyNode(Node node, UpdateType type,
1371             Map<String, Property> propMap) {
1372         synchronized (inventoryListeners) {
1373             for (IInventoryListener service : inventoryListeners) {
1374                 service.notifyNode(node, type, propMap);
1375             }
1376         }
1377     }
1378
1379     private void notifyNodeConnector(NodeConnector nodeConnector,
1380             UpdateType type, Map<String, Property> propMap) {
1381         synchronized (inventoryListeners) {
1382             for (IInventoryListener service : inventoryListeners) {
1383                 service.notifyNodeConnector(nodeConnector, type, propMap);
1384             }
1385         }
1386     }
1387
1388     /*
1389      * For those joined late, bring them up-to-date.
1390      */
1391     private void switchManagerAwareNotify(ISwitchManagerAware service) {
1392         for (Subnet sub : subnets.values()) {
1393             service.subnetNotify(sub, true);
1394         }
1395
1396         for (Node node : getNodes()) {
1397             SwitchConfig sc = getSwitchConfig(node.toString());
1398             if ((sc != null) && isDefaultContainer) {
1399                 service.modeChangeNotify(node, sc.isProactive());
1400             }
1401         }
1402     }
1403
1404     private void bulkUpdateService(IInventoryListener service) {
1405         Map<String, Property> propMap;
1406         UpdateType type = UpdateType.ADDED;
1407
1408         for (Node node : getNodes()) {
1409             propMap = nodeProps.get(node);
1410             service.notifyNode(node, type, propMap);
1411         }
1412
1413         for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
1414             propMap = nodeConnectorProps.get(nodeConnector);
1415             service.notifyNodeConnector(nodeConnector, type, propMap);
1416         }
1417     }
1418
1419     private void spanAwareNotify(ISpanAware service) {
1420         for (Node node : getNodes()) {
1421             for (SpanConfig conf : getSpanConfigList(node)) {
1422                 service.spanUpdate(node, conf.getPortArrayList(), true);
1423             }
1424         }
1425     }
1426
1427     private void registerWithOSGIConsole() {
1428         BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
1429                 .getBundleContext();
1430         bundleContext.registerService(CommandProvider.class.getName(), this,
1431                 null);
1432     }
1433
1434     @Override
1435     public Boolean isNodeConnectorEnabled(NodeConnector nodeConnector) {
1436         if (nodeConnector == null) {
1437             return false;
1438         }
1439
1440         Config config = (Config) getNodeConnectorProp(nodeConnector,
1441                 Config.ConfigPropName);
1442         State state = (State) getNodeConnectorProp(nodeConnector,
1443                 State.StatePropName);
1444         return ((config != null) && (config.getValue() == Config.ADMIN_UP)
1445                 && (state != null) && (state.getValue() == State.EDGE_UP));
1446     }
1447
1448     @Override
1449     public String getHelp() {
1450         StringBuffer help = new StringBuffer();
1451         help.append("---Switch Manager---\n");
1452         help.append("\t pns                    - Print connected nodes\n");
1453         help.append("\t pncs <node id>         - Print node connectors for a given node\n");
1454         help.append("\t pencs <node id>        - Print enabled node connectors for a given node\n");
1455         help.append("\t pdm <node id>          - Print switch ports in device map\n");
1456         help.append("\t snt <node id> <tier>   - Set node tier number\n");
1457         help.append("\t hostRefresh <on/off/?> - Enable/Disable/Query host refresh\n");
1458         help.append("\t hostRetry <count>      - Set host retry count\n");
1459         return help.toString();
1460     }
1461
1462     public void _pns(CommandInterpreter ci) {
1463         ci.println("           Node               Type           MAC            Name      Tier");
1464         if (nodeProps == null) {
1465             return;
1466         }
1467         Set<Node> nodeSet = nodeProps.keySet();
1468         if (nodeSet == null) {
1469             return;
1470         }
1471         for (Node node : nodeSet) {
1472             Description desc = ((Description) getNodeProp(node,
1473                     Description.propertyName));
1474             Tier tier = ((Tier) getNodeProp(node, Tier.TierPropName));
1475             String nodeName = (desc == null) ? "" : desc.getValue();
1476             MacAddress mac = (MacAddress) getNodeProp(node,
1477                     MacAddress.name);
1478             String macAddr = (mac == null) ? "" : HexEncode
1479                     .bytesToHexStringFormat(mac.getMacAddress());
1480             int tierNum = (tier == null) ? 0 : tier.getValue();
1481             ci.println(node + "     " + node.getType() + "     " + macAddr
1482                     + "     " + nodeName + "     " + tierNum);
1483         }
1484         ci.println("Total number of Nodes: " + nodeSet.size());
1485     }
1486
1487     public void _pencs(CommandInterpreter ci) {
1488         String st = ci.nextArgument();
1489         if (st == null) {
1490             ci.println("Please enter node id");
1491             return;
1492         }
1493
1494         Node node = Node.fromString(st);
1495         if (node == null) {
1496             ci.println("Please enter node id");
1497             return;
1498         }
1499
1500         Set<NodeConnector> nodeConnectorSet = getUpNodeConnectors(node);
1501         if (nodeConnectorSet == null) {
1502             return;
1503         }
1504         for (NodeConnector nodeConnector : nodeConnectorSet) {
1505             if (nodeConnector == null) {
1506                 continue;
1507             }
1508             ci.println(nodeConnector);
1509         }
1510         ci.println("Total number of NodeConnectors: " + nodeConnectorSet.size());
1511     }
1512
1513     public void _pncs(CommandInterpreter ci) {
1514         String st = ci.nextArgument();
1515         if (st == null) {
1516             ci.println("Please enter node id");
1517             return;
1518         }
1519
1520         Node node = Node.fromString(st);
1521         if (node == null) {
1522             ci.println("Please enter node id");
1523             return;
1524         }
1525
1526         ci.println("          NodeConnector               BandWidth(Gbps)     Admin     State");
1527         Set<NodeConnector> nodeConnectorSet = getNodeConnectors(node);
1528         if (nodeConnectorSet == null) {
1529             return;
1530         }
1531         for (NodeConnector nodeConnector : nodeConnectorSet) {
1532             if (nodeConnector == null) {
1533                 continue;
1534             }
1535             Map<String, Property> propMap = getNodeConnectorProps(nodeConnector);
1536             Bandwidth bw = (Bandwidth) propMap.get(Bandwidth.BandwidthPropName);
1537             Config config = (Config) propMap.get(Config.ConfigPropName);
1538             State state = (State) propMap.get(State.StatePropName);
1539             String out = nodeConnector + "           ";
1540             out += (bw != null) ? bw.getValue() / Math.pow(10, 9) : "    ";
1541             out += "             ";
1542             out += (config != null) ? config.getValue() : " ";
1543             out += "          ";
1544             out += (state != null) ? state.getValue() : " ";
1545             ci.println(out);
1546         }
1547         ci.println("Total number of NodeConnectors: " + nodeConnectorSet.size());
1548     }
1549
1550     public void _pdm(CommandInterpreter ci) {
1551         String st = ci.nextArgument();
1552         if (st == null) {
1553             ci.println("Please enter node id");
1554             return;
1555         }
1556
1557         Node node = Node.fromString(st);
1558         if (node == null) {
1559             ci.println("Please enter node id");
1560             return;
1561         }
1562
1563         Switch sw = getSwitchByNode(node);
1564
1565         ci.println("          NodeConnector                        Name");
1566         if (sw == null) {
1567             return;
1568         }
1569         Set<NodeConnector> nodeConnectorSet = sw.getNodeConnectors();
1570         String nodeConnectorName;
1571         if (nodeConnectorSet != null && nodeConnectorSet.size() > 0) {
1572             for (NodeConnector nodeConnector : nodeConnectorSet) {
1573                 Map<String, Property> propMap = getNodeConnectorProps(nodeConnector);
1574                 nodeConnectorName = (propMap == null) ? null : ((Name) propMap
1575                         .get(Name.NamePropName)).getValue();
1576                 if (nodeConnectorName != null) {
1577                     Node nd = nodeConnector.getNode();
1578                     if (!nd.equals(node)) {
1579                         log.debug("node not match {} {}", nd, node);
1580                     }
1581                     Map<String, NodeConnector> map = nodeConnectorNames
1582                             .get(node);
1583                     if (map != null) {
1584                         NodeConnector nc = map.get(nodeConnectorName);
1585                         if (nc == null) {
1586                             log.debug("no nodeConnector named {}",
1587                                     nodeConnectorName);
1588                         } else if (!nc.equals(nodeConnector)) {
1589                             log.debug("nodeConnector not match {} {}", nc,
1590                                     nodeConnector);
1591                         }
1592                     }
1593                 }
1594
1595                 ci.println(nodeConnector
1596                         + "            "
1597                         + ((nodeConnectorName == null) ? "" : nodeConnectorName)
1598                         + "(" + nodeConnector.getID() + ")");
1599             }
1600             ci.println("Total number of NodeConnectors: "
1601                     + nodeConnectorSet.size());
1602         }
1603     }
1604
1605     public void _snt(CommandInterpreter ci) {
1606         String st = ci.nextArgument();
1607         if (st == null) {
1608             ci.println("Please enter node id");
1609             return;
1610         }
1611
1612         Node node = Node.fromString(st);
1613         if (node == null) {
1614             ci.println("Please enter node id");
1615             return;
1616         }
1617
1618         st = ci.nextArgument();
1619         if (st == null) {
1620             ci.println("Please enter tier number");
1621             return;
1622         }
1623         Integer tid = Integer.decode(st);
1624         Tier tier = new Tier(tid);
1625         setNodeProp(node, tier);
1626     }
1627
1628     public void _hostRefresh(CommandInterpreter ci) {
1629         String mode = ci.nextArgument();
1630         if (mode == null) {
1631             ci.println("expecting on/off/?");
1632             return;
1633         }
1634         if (mode.toLowerCase().equals("on")) {
1635             hostRefresh = true;
1636         } else if (mode.toLowerCase().equals("off")) {
1637             hostRefresh = false;
1638         } else if (mode.equals("?")) {
1639             if (hostRefresh) {
1640                 ci.println("host refresh is ON");
1641             } else {
1642                 ci.println("host refresh is OFF");
1643             }
1644         } else {
1645             ci.println("expecting on/off/?");
1646         }
1647         return;
1648     }
1649
1650     public void _hostRetry(CommandInterpreter ci) {
1651         String retry = ci.nextArgument();
1652         if (retry == null) {
1653             ci.println("Please enter a valid number. Current retry count is "
1654                     + hostRetryCount);
1655             return;
1656         }
1657         try {
1658             hostRetryCount = Integer.parseInt(retry);
1659         } catch (Exception e) {
1660             ci.println("Please enter a valid number");
1661         }
1662         return;
1663     }
1664
1665     @Override
1666     public byte[] getNodeMAC(Node node) {
1667         MacAddress mac = (MacAddress) this.getNodeProp(node,
1668                 MacAddress.name);
1669         return (mac != null) ? mac.getMacAddress() : null;
1670     }
1671
1672     @Override
1673     public boolean isSpecial(NodeConnector p) {
1674         if (p.getType().equals(NodeConnectorIDType.CONTROLLER)
1675                 || p.getType().equals(NodeConnectorIDType.ALL)
1676                 || p.getType().equals(NodeConnectorIDType.SWSTACK)
1677                 || p.getType().equals(NodeConnectorIDType.HWPATH)) {
1678             return true;
1679         }
1680         return false;
1681     }
1682
1683     /*
1684      * Add span configuration to local cache and notify clients
1685      */
1686     private void addSpanPorts(Node node, List<NodeConnector> nodeConnectors) {
1687         List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
1688
1689         for (NodeConnector nodeConnector : nodeConnectors) {
1690             if (!spanNodeConnectors.contains(nodeConnector)) {
1691                 ncLists.add(nodeConnector);
1692             }
1693         }
1694
1695         if (ncLists.size() > 0) {
1696             spanNodeConnectors.addAll(ncLists);
1697             notifySpanPortChange(node, ncLists, true);
1698         }
1699     }
1700
1701     private void addSpanPorts(Node node) {
1702         for (SpanConfig conf : getSpanConfigList(node)) {
1703             addSpanPorts(node, conf.getPortArrayList());
1704         }
1705     }
1706
1707     private void addSpanPort(NodeConnector nodeConnector) {
1708         // only add if span is configured on this nodeConnector
1709         for (SpanConfig conf : getSpanConfigList(nodeConnector.getNode())) {
1710             if (conf.getPortArrayList().contains(nodeConnector)) {
1711                 List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
1712                 ncLists.add(nodeConnector);
1713                 addSpanPorts(nodeConnector.getNode(), ncLists);
1714                 return;
1715             }
1716         }
1717     }
1718
1719     /*
1720      * Remove span configuration to local cache and notify clients
1721      */
1722     private void removeSpanPorts(Node node, List<NodeConnector> nodeConnectors) {
1723         List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
1724
1725         for (NodeConnector nodeConnector : nodeConnectors) {
1726             if (spanNodeConnectors.contains(nodeConnector)) {
1727                 ncLists.add(nodeConnector);
1728             }
1729         }
1730
1731         if (ncLists.size() > 0) {
1732             spanNodeConnectors.removeAll(ncLists);
1733             notifySpanPortChange(node, ncLists, false);
1734         }
1735     }
1736
1737     private void removeSpanPorts(Node node) {
1738         for (SpanConfig conf : getSpanConfigList(node)) {
1739             addSpanPorts(node, conf.getPortArrayList());
1740         }
1741     }
1742
1743     private void removeSpanPort(NodeConnector nodeConnector) {
1744         if (spanNodeConnectors.contains(nodeConnector)) {
1745             List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
1746             ncLists.add(nodeConnector);
1747             removeSpanPorts(nodeConnector.getNode(), ncLists);
1748         }
1749     }
1750
1751     private void addNodeProps(Node node, Map<String, Property> propMap) {
1752         if (propMap == null) {
1753             propMap = new HashMap<String, Property>();
1754         }
1755         nodeProps.put(node, propMap);
1756     }
1757
1758     private void removeNodeProps(Node node) {
1759         if (getUpNodeConnectors(node).size() == 0) {
1760             nodeProps.remove(node);
1761         }
1762     }
1763
1764     @Override
1765     public Status saveConfiguration() {
1766         return saveSwitchConfig();
1767     }
1768
1769     /**
1770      * Creates a Name/Tier/Bandwidth Property object based on given property
1771      * name and value. Other property types are not supported yet.
1772      *
1773      * @param propName
1774      *            Name of the Property
1775      * @param propValue
1776      *            Value of the Property
1777      * @return {@link org.opendaylight.controller.sal.core.Property}
1778      */
1779     @Override
1780     public Property createProperty(String propName, String propValue) {
1781         if (propName == null) {
1782             log.debug("propName is null");
1783             return null;
1784         }
1785         if (propValue == null) {
1786             log.debug("propValue is null");
1787             return null;
1788         }
1789
1790         try {
1791             if (propName.equalsIgnoreCase(Description.propertyName)) {
1792                 return new Description(propValue);
1793             } else if (propName.equalsIgnoreCase(Tier.TierPropName)) {
1794                 int tier = Integer.parseInt(propValue);
1795                 return new Tier(tier);
1796             } else if (propName.equalsIgnoreCase(Bandwidth.BandwidthPropName)) {
1797                 long bw = Long.parseLong(propValue);
1798                 return new Bandwidth(bw);
1799             } else {
1800                 log.debug("Not able to create {} property", propName);
1801             }
1802         } catch (Exception e) {
1803             log.debug("createProperty caught exception {}", e.getMessage());
1804         }
1805
1806         return null;
1807     }
1808
1809     @Override
1810     public String getNodeDescription(Node node) {
1811         // Check first if user configured a name
1812         SwitchConfig config = getSwitchConfig(node.toString());
1813         if (config != null) {
1814             String configuredDesc = config.getNodeDescription();
1815             if (configuredDesc != null && !configuredDesc.isEmpty()) {
1816                 return configuredDesc;
1817             }
1818         }
1819
1820         // No name configured by user, get the node advertised name
1821         Description desc = (Description) getNodeProp(node,
1822                 Description.propertyName);
1823         return (desc == null /* || desc.getValue().equalsIgnoreCase("none") */) ? ""
1824                 : desc.getValue();
1825     }
1826 }