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