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