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