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