Merge "Moved parsing of unknown nodes from implementation to abstract classes."
[controller.git] / opendaylight / hosttracker / implementation / src / main / java / org / opendaylight / controller / hosttracker / internal / HostTracker.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.hosttracker.internal;
10
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.Dictionary;
16 import java.util.EnumSet;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import java.util.Set;
22 import java.util.Timer;
23 import java.util.TimerTask;
24 import java.util.concurrent.Callable;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.Executors;
29 import java.util.concurrent.Future;
30
31 import org.apache.felix.dm.Component;
32 import org.opendaylight.controller.clustering.services.CacheConfigException;
33 import org.opendaylight.controller.clustering.services.CacheExistException;
34 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
35 import org.opendaylight.controller.clustering.services.IClusterServices;
36 import org.opendaylight.controller.hosttracker.IfHostListener;
37 import org.opendaylight.controller.hosttracker.IfIptoHost;
38 import org.opendaylight.controller.hosttracker.IfNewHostNotify;
39 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
40 import org.opendaylight.controller.hosttracker.hostAware.IHostFinder;
41 import org.opendaylight.controller.sal.core.ConstructionException;
42 import org.opendaylight.controller.sal.core.Edge;
43 import org.opendaylight.controller.sal.core.Host;
44 import org.opendaylight.controller.sal.core.Node;
45 import org.opendaylight.controller.sal.core.NodeConnector;
46 import org.opendaylight.controller.sal.core.Property;
47 import org.opendaylight.controller.sal.core.State;
48 import org.opendaylight.controller.sal.core.Tier;
49 import org.opendaylight.controller.sal.core.UpdateType;
50 import org.opendaylight.controller.sal.packet.address.DataLinkAddress;
51 import org.opendaylight.controller.sal.packet.address.EthernetAddress;
52 import org.opendaylight.controller.sal.topology.TopoEdgeUpdate;
53 import org.opendaylight.controller.sal.utils.GlobalConstants;
54 import org.opendaylight.controller.sal.utils.HexEncode;
55 import org.opendaylight.controller.sal.utils.NetUtils;
56 import org.opendaylight.controller.sal.utils.NodeCreator;
57 import org.opendaylight.controller.sal.utils.Status;
58 import org.opendaylight.controller.sal.utils.StatusCode;
59 import org.opendaylight.controller.switchmanager.IInventoryListener;
60 import org.opendaylight.controller.switchmanager.ISwitchManager;
61 import org.opendaylight.controller.switchmanager.ISwitchManagerAware;
62 import org.opendaylight.controller.switchmanager.Subnet;
63 import org.opendaylight.controller.topologymanager.ITopologyManager;
64 import org.opendaylight.controller.topologymanager.ITopologyManagerAware;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67
68 /**
69  * @file HostTracker.java This class tracks the location of IP Hosts as to which
70  *       Switch, Port, VLAN, they are connected to, as well as their MAC
71  *       address. This is done dynamically as well as statically. The dynamic
72  *       mechanism consists of listening to ARP messages as well sending ARP
73  *       requests. Static mechanism consists of Northbound APIs to add or remove
74  *       the hosts from the local database. ARP aging is also implemented to age
75  *       out dynamically learned hosts. Interface methods are provided for other
76  *       applications to 1. Query the local database for a single host 2. Get a
77  *       list of all hosts 3. Get notification if a host is learned/added or
78  *       removed the database
79  */
80
81 public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAware, IInventoryListener,
82         ITopologyManagerAware {
83     private static final Logger logger = LoggerFactory.getLogger(HostTracker.class);
84     private IHostFinder hostFinder;
85     private ConcurrentMap<InetAddress, HostNodeConnector> hostsDB;
86     /*
87      * Following is a list of hosts which have been requested by NB APIs to be
88      * added, but either the switch or the port is not sup, so they will be
89      * added here until both come up
90      */
91     private ConcurrentMap<NodeConnector, HostNodeConnector> inactiveStaticHosts;
92     private final Set<IfNewHostNotify> newHostNotify = Collections.synchronizedSet(new HashSet<IfNewHostNotify>());
93
94     private ITopologyManager topologyManager;
95     private IClusterContainerServices clusterContainerService = null;
96     private ISwitchManager switchManager = null;
97     private Timer timer;
98     private Timer arp_refresh_timer;
99     private String containerName = null;
100
101     private static class ARPPending {
102         protected InetAddress hostIP;
103         protected short sent_count;
104         protected HostTrackerCallable hostTrackerCallable;
105
106         public InetAddress getHostIP() {
107             return hostIP;
108         }
109
110         public short getSent_count() {
111             return sent_count;
112         }
113
114         public HostTrackerCallable getHostTrackerCallable() {
115             return hostTrackerCallable;
116         }
117
118         public void setHostIP(InetAddress networkAddr) {
119             this.hostIP = networkAddr;
120         }
121
122         public void setSent_count(short count) {
123             this.sent_count = count;
124         }
125
126         public void setHostTrackerCallable(HostTrackerCallable callable) {
127             hostTrackerCallable = callable;
128         }
129     }
130
131     // This list contains the hosts for which ARP requests are being sent
132     // periodically
133     private final List<ARPPending> ARPPendingList = new ArrayList<HostTracker.ARPPending>();
134     /*
135      * This list below contains the hosts which were initially in ARPPendingList
136      * above, but ARP response didn't come from there hosts after multiple
137      * attempts over 8 seconds. The assumption is that the response didn't come
138      * back due to one of the following possibilities: 1. The L3 interface
139      * wasn't created for this host in the controller. This would cause
140      * arphandler not to know where to send the ARP 2. The host facing port is
141      * down 3. The IP host doesn't exist or is not responding to ARP requests
142      *
143      * Conditions 1 and 2 above can be recovered if ARP is sent when the
144      * relevant L3 interface is added or the port facing host comes up. Whenever
145      * L3 interface is added or host facing port comes up, ARP will be sent to
146      * hosts in this list.
147      *
148      * We can't recover from condition 3 above
149      */
150     private final ArrayList<ARPPending> failedARPReqList = new ArrayList<HostTracker.ARPPending>();
151
152     public HostTracker() {
153     }
154
155     private void startUp() {
156         allocateCache();
157         retrieveCache();
158
159         timer = new Timer();
160         timer.schedule(new OutStandingARPHandler(), 4000, 4000);
161
162         /* ARP Refresh Timer to go off every 5 seconds to implement ARP aging */
163         arp_refresh_timer = new Timer();
164         arp_refresh_timer.schedule(new ARPRefreshHandler(), 5000, 5000);
165         logger.debug("startUp: Caches created, timers started");
166     }
167
168     @SuppressWarnings("deprecation")
169     private void allocateCache() {
170         if (this.clusterContainerService == null) {
171             logger.error("un-initialized clusterContainerService, can't create cache");
172             return;
173         }
174         logger.debug("Creating Cache for HostTracker");
175         try {
176             this.clusterContainerService.createCache("hostTrackerAH",
177                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
178             this.clusterContainerService.createCache("hostTrackerIH",
179                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
180         } catch (CacheConfigException cce) {
181             logger.error("Cache couldn't be created for HostTracker -  check cache mode");
182         } catch (CacheExistException cce) {
183             logger.error("Cache for HostTracker already exists, destroy and recreate");
184         }
185         logger.debug("Cache successfully created for HostTracker");
186     }
187
188     @SuppressWarnings({ "unchecked", "deprecation" })
189     private void retrieveCache() {
190         if (this.clusterContainerService == null) {
191             logger.error("un-initialized clusterContainerService, can't retrieve cache");
192             return;
193         }
194         logger.debug("Retrieving cache for HostTrackerAH");
195         hostsDB = (ConcurrentMap<InetAddress, HostNodeConnector>) this.clusterContainerService
196                 .getCache("hostTrackerAH");
197         if (hostsDB == null) {
198             logger.error("Cache couldn't be retrieved for HostTracker");
199         }
200         logger.debug("Cache was successfully retrieved for HostTracker");
201         logger.debug("Retrieving cache for HostTrackerIH");
202         inactiveStaticHosts = (ConcurrentMap<NodeConnector, HostNodeConnector>) this.clusterContainerService
203                 .getCache("hostTrackerIH");
204         if (inactiveStaticHosts == null) {
205             logger.error("Cache couldn't be retrieved for HostTrackerIH");
206         }
207         logger.debug("Cache was successfully retrieved for HostTrackerIH");
208     }
209
210     public void nonClusterObjectCreate() {
211         hostsDB = new ConcurrentHashMap<InetAddress, HostNodeConnector>();
212         inactiveStaticHosts = new ConcurrentHashMap<NodeConnector, HostNodeConnector>();
213     }
214
215     @SuppressWarnings("deprecation")
216     private void destroyCache() {
217         if (this.clusterContainerService == null) {
218             logger.error("un-initialized clusterMger, can't destroy cache");
219             return;
220         }
221         logger.debug("Destroying Cache for HostTracker");
222         this.clusterContainerService.destroyCache("hostTrackerAH");
223         this.clusterContainerService.destroyCache("hostTrackerIH");
224         nonClusterObjectCreate();
225     }
226
227     public void shutDown() {
228     }
229
230     public void setnewHostNotify(IfNewHostNotify obj) {
231         this.newHostNotify.add(obj);
232     }
233
234     public void unsetnewHostNotify(IfNewHostNotify obj) {
235         this.newHostNotify.remove(obj);
236     }
237
238     public void setArpHandler(IHostFinder hostFinder) {
239         this.hostFinder = hostFinder;
240     }
241
242     public void unsetArpHandler(IHostFinder hostFinder) {
243         if (this.hostFinder == hostFinder) {
244             logger.debug("Arp Handler Service removed!");
245             this.hostFinder = null;
246         }
247     }
248
249     public void setTopologyManager(ITopologyManager s) {
250         this.topologyManager = s;
251     }
252
253     public void unsetTopologyManager(ITopologyManager s) {
254         if (this.topologyManager == s) {
255             logger.debug("Topology Manager Service removed!");
256             this.topologyManager = null;
257         }
258     }
259
260     private boolean hostExists(HostNodeConnector host) {
261         HostNodeConnector lhost = hostsDB.get(host.getNetworkAddress());
262         return host.equals(lhost);
263     }
264
265     private HostNodeConnector getHostFromOnActiveDB(InetAddress networkAddress) {
266         return hostsDB.get(networkAddress);
267     }
268
269     private Entry<NodeConnector, HostNodeConnector> getHostFromInactiveDB(InetAddress networkAddress) {
270         for (Entry<NodeConnector, HostNodeConnector> entry : inactiveStaticHosts.entrySet()) {
271             if (entry.getValue().equalsByIP(networkAddress)) {
272                 logger.debug("getHostFromInactiveDB(): Inactive Host found for IP:{} ", networkAddress.getHostAddress());
273                 return entry;
274             }
275         }
276         logger.debug("getHostFromInactiveDB() Inactive Host Not found for IP: {}", networkAddress.getHostAddress());
277         return null;
278     }
279
280     private void removeHostFromInactiveDB(InetAddress networkAddress) {
281         NodeConnector nodeConnector = null;
282         for (Entry<NodeConnector, HostNodeConnector> entry : inactiveStaticHosts.entrySet()) {
283             if (entry.getValue().equalsByIP(networkAddress)) {
284                 nodeConnector = entry.getKey();
285                 break;
286             }
287         }
288         if (nodeConnector != null) {
289             inactiveStaticHosts.remove(nodeConnector);
290             logger.debug("removeHostFromInactiveDB(): Host Removed for IP: {}", networkAddress.getHostAddress());
291             return;
292         }
293         logger.debug("removeHostFromInactiveDB(): Host Not found for IP: {}", networkAddress.getHostAddress());
294     }
295
296     protected boolean hostMoved(HostNodeConnector host) {
297         if (hostQuery(host.getNetworkAddress()) != null) {
298             return true;
299         }
300         return false;
301     }
302
303     @Override
304     public HostNodeConnector hostQuery(InetAddress networkAddress) {
305         return hostsDB.get(networkAddress);
306     }
307
308     @Override
309     public Future<HostNodeConnector> discoverHost(InetAddress networkAddress) {
310         ExecutorService executor = Executors.newFixedThreadPool(1);
311         if (executor == null) {
312             logger.error("discoverHost: Null executor");
313             return null;
314         }
315         Callable<HostNodeConnector> worker = new HostTrackerCallable(this, networkAddress);
316         Future<HostNodeConnector> submit = executor.submit(worker);
317         return submit;
318     }
319
320     @Override
321     public HostNodeConnector hostFind(InetAddress networkAddress) {
322         /*
323          * Sometimes at boot with containers configured in the startup we hit
324          * this path (from TIF) when hostFinder has not been set yet Caller
325          * already handles the null return
326          */
327
328         if (hostFinder == null) {
329             logger.debug("Exiting hostFind, null hostFinder");
330             return null;
331         }
332
333         HostNodeConnector host = hostQuery(networkAddress);
334         if (host != null) {
335             logger.debug("hostFind(): Host found for IP: {}", networkAddress.getHostAddress());
336             return host;
337         }
338         /* host is not found, initiate a discovery */
339         hostFinder.find(networkAddress);
340         /* Also add this host to ARPPending List for any potential retries */
341         AddtoARPPendingList(networkAddress);
342         logger.debug("hostFind(): Host Not Found for IP: {}, Inititated Host Discovery ...",
343                 networkAddress.getHostAddress());
344         return null;
345     }
346
347     @Override
348     public Set<HostNodeConnector> getAllHosts() {
349         Set<HostNodeConnector> allHosts = new HashSet<HostNodeConnector>();
350         for (Entry<InetAddress, HostNodeConnector> entry : hostsDB.entrySet()) {
351             HostNodeConnector host = entry.getValue();
352             allHosts.add(host);
353         }
354         logger.debug("Exiting getAllHosts, Found {} Hosts", allHosts.size());
355         return allHosts;
356     }
357
358     @Override
359     public Set<HostNodeConnector> getActiveStaticHosts() {
360         Set<HostNodeConnector> list = new HashSet<HostNodeConnector>();
361         for (Entry<InetAddress, HostNodeConnector> entry : hostsDB.entrySet()) {
362             HostNodeConnector host = entry.getValue();
363             if (host.isStaticHost()) {
364                 list.add(host);
365             }
366         }
367         logger.debug("getActiveStaticHosts(): Found {} Hosts", list.size());
368         return list;
369     }
370
371     @Override
372     public Set<HostNodeConnector> getInactiveStaticHosts() {
373         Set<HostNodeConnector> list = new HashSet<HostNodeConnector>();
374         for (Entry<NodeConnector, HostNodeConnector> entry : inactiveStaticHosts.entrySet()) {
375             list.add(entry.getValue());
376         }
377         logger.debug("getInactiveStaticHosts(): Found {} Hosts", list.size());
378         return list;
379     }
380
381     private void AddtoARPPendingList(InetAddress networkAddr) {
382         ARPPending arphost = new ARPPending();
383
384         arphost.setHostIP(networkAddr);
385         arphost.setSent_count((short) 1);
386         ARPPendingList.add(arphost);
387         logger.debug("Host Added to ARPPending List, IP: {}", networkAddr);
388     }
389
390     private void removePendingARPFromList(int index) {
391         if (index >= ARPPendingList.size()) {
392             logger.warn("removePendingARPFromList(): index greater than the List. Size:{}, Index:{}",
393                     ARPPendingList.size(), index);
394             return;
395         }
396         ARPPending arphost = ARPPendingList.remove(index);
397         HostTrackerCallable htCallable = arphost.getHostTrackerCallable();
398         if (htCallable != null)
399             htCallable.wakeup();
400     }
401
402     public void setCallableOnPendingARP(InetAddress networkAddr, HostTrackerCallable callable) {
403         ARPPending arphost;
404         for (int i = 0; i < ARPPendingList.size(); i++) {
405             arphost = ARPPendingList.get(i);
406             if (arphost.getHostIP().equals(networkAddr)) {
407                 arphost.setHostTrackerCallable(callable);
408             }
409         }
410     }
411
412     private void ProcPendingARPReqs(InetAddress networkAddr) {
413         ARPPending arphost;
414
415         for (int i = 0; i < ARPPendingList.size(); i++) {
416             arphost = ARPPendingList.get(i);
417             if (arphost.getHostIP().equals(networkAddr)) {
418                 /*
419                  * An ARP was sent for this host. The address is learned, remove
420                  * the request
421                  */
422                 removePendingARPFromList(i);
423                 logger.debug("Host Removed from ARPPending List, IP: {}", networkAddr);
424                 return;
425             }
426         }
427
428         /*
429          * It could have been a host from the FailedARPReqList
430          */
431
432         for (int i = 0; i < failedARPReqList.size(); i++) {
433             arphost = failedARPReqList.get(i);
434             if (arphost.getHostIP().equals(networkAddr)) {
435                 /*
436                  * An ARP was sent for this host. The address is learned, remove
437                  * the request
438                  */
439                 failedARPReqList.remove(i);
440                 logger.debug("Host Removed from FailedARPReqList List, IP: {}", networkAddr);
441                 return;
442             }
443         }
444     }
445
446     // Learn a new Host
447     private void learnNewHost(HostNodeConnector host) {
448         host.initArpSendCountDown();
449         HostNodeConnector rHost = hostsDB.putIfAbsent(host.getNetworkAddress(), host);
450         if (rHost != null) {
451             // Another host is already learned for this IP address, replace it
452             replaceHost(host.getNetworkAddress(), rHost, host);
453         } else {
454             logger.debug("New Host Learned: MAC: {}  IP: {}", HexEncode.bytesToHexString(host
455                     .getDataLayerAddressBytes()), host.getNetworkAddress().getHostAddress());
456         }
457     }
458
459     private void replaceHost(InetAddress networkAddr, HostNodeConnector removedHost, HostNodeConnector newHost) {
460         newHost.initArpSendCountDown();
461         if (hostsDB.replace(networkAddr, removedHost, newHost)) {
462             logger.debug("Host move occurred. Old Host:{}, New Host: {}", removedHost, newHost);
463         } else {
464             /*
465              * Host replacement has failed, do the recovery
466              */
467             hostsDB.put(networkAddr, newHost);
468             logger.error("Host replacement failed. Overwrite the host. Repalced Host: {}, New Host: {}", removedHost,
469                     newHost);
470         }
471         notifyHostLearnedOrRemoved(removedHost, false);
472         notifyHostLearnedOrRemoved(newHost, true);
473         if (!newHost.isStaticHost()) {
474             ProcPendingARPReqs(networkAddr);
475         }
476     }
477
478     // Remove known Host
479     private void removeKnownHost(InetAddress key) {
480         HostNodeConnector host = hostsDB.get(key);
481         if (host != null) {
482             logger.debug("Removing Host: IP:{}", host.getNetworkAddress().getHostAddress());
483             hostsDB.remove(key);
484         } else {
485             logger.error("removeKnownHost(): Host for IP address {} not found in hostsDB", key.getHostAddress());
486         }
487     }
488
489     private class NotifyHostThread extends Thread {
490
491         private final HostNodeConnector host;
492
493         public NotifyHostThread(HostNodeConnector h) {
494             this.host = h;
495         }
496
497         @Override
498         public void run() {
499             HostNodeConnector removedHost = null;
500             InetAddress networkAddr = host.getNetworkAddress();
501
502             /* Check for Host Move case */
503             if (hostMoved(host)) {
504                 /*
505                  * Host has been moved from one location (switch,port, MAC, or
506                  * VLAN) to another. Replace the existing host and its previous
507                  * location parameters with new information, and notify the
508                  * applications listening to host move.
509                  */
510                 removedHost = hostsDB.get(networkAddr);
511                 if (removedHost != null) {
512                     replaceHost(networkAddr, removedHost, host);
513                     return;
514                 } else {
515                     logger.error("Host to be removed not found in hostsDB. Host {}", removedHost);
516                 }
517             }
518
519             if (removedHost == null) {
520                 // It is a new host
521                 learnNewHost(host);
522             }
523
524             /* check if there is an outstanding request for this host */
525             ProcPendingARPReqs(networkAddr);
526             notifyHostLearnedOrRemoved(host, true);
527         }
528     }
529
530     @Override
531     public void hostListener(HostNodeConnector host) {
532
533         if (hostExists(host)) {
534             logger.debug("ARP received for Host: {}", host);
535             HostNodeConnector existinghost = hostsDB.get(host.getNetworkAddress());
536             existinghost.initArpSendCountDown();
537             return;
538         }
539         new NotifyHostThread(host).start();
540     }
541
542     // Notify whoever is interested that a new host was learned (dynamically or
543     // statically)
544     private void notifyHostLearnedOrRemoved(HostNodeConnector host, boolean add) {
545         // Update listeners if any
546         if (newHostNotify != null) {
547             synchronized (this.newHostNotify) {
548                 for (IfNewHostNotify ta : newHostNotify) {
549                     try {
550                         if (add) {
551                             ta.notifyHTClient(host);
552                         } else {
553                             ta.notifyHTClientHostRemoved(host);
554                         }
555                     } catch (Exception e) {
556                         logger.error("Exception on callback", e);
557                     }
558                 }
559             }
560         } else {
561             logger.error("notifyHostLearnedOrRemoved(): New host notify is null");
562         }
563
564         // Topology update is for some reason outside of listeners registry
565         // logic
566         Node node = host.getnodeconnectorNode();
567         Host h = null;
568         NodeConnector p = host.getnodeConnector();
569         try {
570             DataLinkAddress dla = new EthernetAddress(host.getDataLayerAddressBytes());
571             h = new Host(dla, host.getNetworkAddress());
572         } catch (ConstructionException ce) {
573             p = null;
574             h = null;
575         }
576
577         if (topologyManager != null && p != null && h != null) {
578             if (add == true) {
579                 Tier tier = new Tier(1);
580                 switchManager.setNodeProp(node, tier);
581                 topologyManager.updateHostLink(p, h, UpdateType.ADDED, null);
582             } else {
583                 // No need to reset the tiering if no other hosts are currently
584                 // connected
585                 // If this switch was discovered to be an access switch, it
586                 // still is even if the host is down
587                 Tier tier = new Tier(0);
588                 switchManager.setNodeProp(node, tier);
589                 topologyManager.updateHostLink(p, h, UpdateType.REMOVED, null);
590             }
591         }
592     }
593
594     /**
595      * When a new Host is learnt by the hosttracker module, it places the
596      * directly connected Node in Tier-1 & using this function, updates the Tier
597      * value for all other Nodes in the network hierarchy.
598      *
599      * This is a recursive function and it takes care of updating the Tier value
600      * for all the connected and eligible Nodes.
601      *
602      * @param n
603      *            Node that represents one of the Vertex in the Topology Graph.
604      * @param currentTier
605      *            The Tier on which n belongs
606      */
607     private void updateSwitchTiers(Node n, int currentTier) {
608         Map<Node, Set<Edge>> ndlinks = topologyManager.getNodeEdges();
609         if (ndlinks == null) {
610             logger.debug("updateSwitchTiers(): ndlinks null for Node: {}, Tier:{}", n, currentTier);
611             return;
612         }
613         Set<Edge> links = ndlinks.get(n);
614         if (links == null) {
615             logger.debug("updateSwitchTiers(): links null for ndlinks:{}", ndlinks);
616             return;
617         }
618         ArrayList<Node> needsVisiting = new ArrayList<Node>();
619         for (Edge lt : links) {
620             if (!lt.getHeadNodeConnector().getType().equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
621                 // We don't want to work on Node that are not openflow
622                 // for now
623                 continue;
624             }
625             Node dstNode = lt.getHeadNodeConnector().getNode();
626             if (switchNeedsTieringUpdate(dstNode, currentTier + 1)) {
627                 Tier t = new Tier(currentTier + 1);
628                 switchManager.setNodeProp(dstNode, t);
629                 needsVisiting.add(dstNode);
630             }
631         }
632
633         /*
634          * Due to the nature of the problem, having a separate loop for nodes
635          * that needs visiting provides a decent walk optimization.
636          */
637         for (Node node : needsVisiting) {
638             updateSwitchTiers(node, currentTier + 1);
639         }
640     }
641
642     /**
643      * Internal convenience routine to check the eligibility of a Switch for a
644      * Tier update. Any Node with Tier=0 or a Tier value that is greater than
645      * the new Tier Value is eligible for the update.
646      *
647      * @param n
648      *            Node for which the Tier update eligibility is checked
649      * @param tier
650      *            new Tier Value
651      * @return <code>true</code> if the Node is eligible for Tier Update
652      *         <code>false</code> otherwise
653      */
654
655     private boolean switchNeedsTieringUpdate(Node n, int tier) {
656         if (n == null) {
657             logger.error("switchNeedsTieringUpdate(): Null node for tier: {}", tier);
658             return false;
659         }
660         /*
661          * Node could have gone down
662          */
663         if (!switchManager.getNodes().contains(n)) {
664             return false;
665         }
666         // This is the case where Tier was never set for this node
667         Tier t = (Tier) switchManager.getNodeProp(n, Tier.TierPropName);
668         if (t == null)
669             return true;
670         if (t.getValue() == 0)
671             return true;
672         else if (t.getValue() > tier)
673             return true;
674         return false;
675     }
676
677     /**
678      * Internal convenience routine to clear all the Tier values to 0. This
679      * cleanup is performed during cases such as Topology Change where the
680      * existing Tier values might become incorrect
681      */
682     private void clearTiers() {
683         Set<Node> nodes = null;
684         if (switchManager == null) {
685             logger.error("clearTiers(): Null switchManager");
686             return;
687         }
688         nodes = switchManager.getNodes();
689
690         for (Node n : nodes) {
691             Tier t = new Tier(0);
692             switchManager.setNodeProp(n, t);
693         }
694     }
695
696     /**
697      * Internal convenience routine to print the hierarchies of switches.
698      */
699     @SuppressWarnings("unused")
700     private void logHierarchies(ArrayList<ArrayList<String>> hierarchies) {
701         String hierarchyString = null;
702         int num = 1;
703         for (ArrayList<String> hierarchy : hierarchies) {
704             StringBuffer buf = new StringBuffer();
705             buf.append("Hierarchy#" + num + " : ");
706             for (String switchName : hierarchy) {
707                 buf.append(switchName + "/");
708             }
709             logger.debug("{} -> {}", getContainerName(), buf);
710             num++;
711         }
712     }
713
714     /**
715      * getHostNetworkHierarchy is the Back-end routine for the North-Bound API
716      * that returns the Network Hierarchy for a given Host. This API is
717      * typically used by applications like Hadoop for Rack Awareness
718      * functionality.
719      *
720      * @param hostAddress
721      *            IP-Address of the host/node.
722      * @return Network Hierarchies represented by an Array of Array (of
723      *         Switch-Ids as String).
724      */
725     @Override
726     public List<List<String>> getHostNetworkHierarchy(InetAddress hostAddress) {
727         HostNodeConnector host = hostQuery(hostAddress);
728         if (host == null)
729             return null;
730
731         List<List<String>> hierarchies = new ArrayList<List<String>>();
732         ArrayList<String> currHierarchy = new ArrayList<String>();
733         hierarchies.add(currHierarchy);
734
735         Node node = host.getnodeconnectorNode();
736         updateCurrentHierarchy(node, currHierarchy, hierarchies);
737         return hierarchies;
738     }
739
740     /**
741      * dpidToHostNameHack is a hack function for Cisco Live Hadoop Demo. Mininet
742      * is used as the network for Hadoop Demos & in order to give a meaningful
743      * rack-awareness switch names, the DPID is organized in ASCII Characters
744      * and retrieved as string.
745      *
746      * @param dpid
747      *            Switch DataPath Id
748      * @return Ascii String represented by the DPID.
749      */
750     private String dpidToHostNameHack(long dpid) {
751         String hex = Long.toHexString(dpid);
752
753         StringBuffer sb = new StringBuffer();
754         int result = 0;
755         for (int i = 0; i < hex.length(); i++) {
756             result = (int) ((dpid >> (i * 8)) & 0xff);
757             if (result == 0)
758                 continue;
759             if (result < 0x30)
760                 result += 0x40;
761             sb.append(String.format("%c", result));
762         }
763         return sb.reverse().toString();
764     }
765
766     /**
767      * A convenient recursive routine to obtain the Hierarchy of Switches.
768      *
769      * @param node
770      *            Current Node in the Recursive routine.
771      * @param currHierarchy
772      *            Array of Nodes that make this hierarchy on which the Current
773      *            Switch belong
774      * @param fullHierarchy
775      *            Array of multiple Hierarchies that represent a given host.
776      */
777     @SuppressWarnings("unchecked")
778     private void updateCurrentHierarchy(Node node, ArrayList<String> currHierarchy, List<List<String>> fullHierarchy) {
779         // currHierarchy.add(String.format("%x", currSw.getId()));
780         currHierarchy.add(dpidToHostNameHack((Long) node.getID()));
781         ArrayList<String> currHierarchyClone = (ArrayList<String>) currHierarchy.clone(); // Shallow
782                                                                                           // copy
783                                                                                           // as
784                                                                                           // required
785
786         Map<Node, Set<Edge>> ndlinks = topologyManager.getNodeEdges();
787         if (ndlinks == null) {
788             logger.debug("updateCurrentHierarchy(): topologyManager returned null ndlinks for node: {}", node);
789             return;
790         }
791         Node n = NodeCreator.createOFNode((Long) node.getID());
792         Set<Edge> links = ndlinks.get(n);
793         if (links == null) {
794             logger.debug("updateCurrentHierarchy(): Null links for ndlinks");
795             return;
796         }
797         for (Edge lt : links) {
798             if (!lt.getHeadNodeConnector().getType().equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
799                 // We don't want to work on Node that are not openflow
800                 // for now
801                 continue;
802             }
803             Node dstNode = lt.getHeadNodeConnector().getNode();
804
805             Tier nodeTier = (Tier) switchManager.getNodeProp(node, Tier.TierPropName);
806             Tier dstNodeTier = (Tier) switchManager.getNodeProp(dstNode, Tier.TierPropName);
807             if (dstNodeTier.getValue() > nodeTier.getValue()) {
808                 ArrayList<String> buildHierarchy = currHierarchy;
809                 if (currHierarchy.size() > currHierarchyClone.size()) {
810                     buildHierarchy = (ArrayList<String>) currHierarchyClone.clone(); // Shallow
811                                                                                      // copy
812                                                                                      // as
813                                                                                      // required
814                     fullHierarchy.add(buildHierarchy);
815                 }
816                 updateCurrentHierarchy(dstNode, buildHierarchy, fullHierarchy);
817             }
818         }
819     }
820
821     private void edgeUpdate(Edge e, UpdateType type, Set<Property> props) {
822         Long srcNid = null;
823         Short srcPort = null;
824         Long dstNid = null;
825         Short dstPort = null;
826         boolean added = false;
827         String srcType = null;
828         String dstType = null;
829
830         if (e == null || type == null) {
831             logger.error("Edge or Update type are null!");
832             return;
833         } else {
834             srcType = e.getTailNodeConnector().getType();
835             dstType = e.getHeadNodeConnector().getType();
836
837             if (srcType.equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) {
838                 logger.debug("Skip updates for {}", e);
839                 return;
840             }
841
842             if (!srcType.equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
843                 logger.error("For now we cannot handle updates for " + "non-openflow nodes");
844                 return;
845             }
846
847             if (dstType.equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) {
848                 logger.debug("Skip updates for {}", e);
849                 return;
850             }
851
852             if (!dstType.equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
853                 logger.error("For now we cannot handle updates for " + "non-openflow nodes");
854                 return;
855             }
856
857             // At this point we know we got an openflow update, so
858             // lets fill everything accordingly.
859             srcNid = (Long) e.getTailNodeConnector().getNode().getID();
860             srcPort = (Short) e.getTailNodeConnector().getID();
861             dstNid = (Long) e.getHeadNodeConnector().getNode().getID();
862             dstPort = (Short) e.getHeadNodeConnector().getID();
863
864             // Now lets update the added flag
865             switch (type) {
866             case ADDED:
867             case CHANGED:
868                 added = true;
869                 break;
870             case REMOVED:
871                 added = false;
872             }
873         }
874
875         logger.debug("HostTracker Topology linkUpdate handling src:{}[port {}] dst:{}[port {}] added: {}",
876                 new Object[] { srcNid, srcPort, dstNid, dstPort, added });
877     }
878
879     @Override
880     public void edgeUpdate(List<TopoEdgeUpdate> topoedgeupdateList) {
881         for (int i = 0; i < topoedgeupdateList.size(); i++) {
882             Edge e = topoedgeupdateList.get(i).getEdge();
883             Set<Property> p = topoedgeupdateList.get(i).getProperty();
884             UpdateType type = topoedgeupdateList.get(i).getUpdateType();
885             edgeUpdate(e, type, p);
886         }
887     }
888
889     @Override
890     public void subnetNotify(Subnet sub, boolean add) {
891         logger.debug("Received subnet notification: {}  add={}", sub, add);
892         if (add) {
893             for (int i = 0; i < failedARPReqList.size(); i++) {
894                 ARPPending arphost;
895                 arphost = failedARPReqList.get(i);
896                 logger.debug("Sending the ARP from FailedARPReqList fors IP: {}", arphost.getHostIP().getHostAddress());
897                 hostFinder.find(arphost.getHostIP());
898             }
899         }
900     }
901
902     class OutStandingARPHandler extends TimerTask {
903         @Override
904         public void run() {
905             ARPPending arphost;
906             /* This routine runs every 4 seconds */
907             // logger.info ("ARP Handler called");
908             for (int i = 0; i < ARPPendingList.size(); i++) {
909                 arphost = ARPPendingList.get(i);
910                 if (arphost.getSent_count() < switchManager.getHostRetryCount()) {
911                     /*
912                      * No reply has been received of first ARP Req, send the
913                      * next one
914                      */
915                     hostFinder.find(arphost.getHostIP());
916                     arphost.sent_count++;
917                     logger.debug("ARP Sent from ARPPending List, IP: {}", arphost.getHostIP().getHostAddress());
918                 } else if (arphost.getSent_count() >= switchManager.getHostRetryCount()) {
919                     /*
920                      * Two ARP requests have been sent without receiving a
921                      * reply, remove this from the pending list
922                      */
923                     removePendingARPFromList(i);
924                     logger.debug("ARP reply not received after two attempts, removing from Pending List IP: {}",
925                             arphost.getHostIP().getHostAddress());
926                     /*
927                      * Add this host to a different list which will be processed
928                      * on link up events
929                      */
930                     logger.debug("Adding the host to FailedARPReqList IP: {}", arphost.getHostIP().getHostAddress());
931                     failedARPReqList.add(arphost);
932
933                 } else {
934                     logger.error("Inavlid arp_sent count for entery at index: {}", i);
935                 }
936             }
937         }
938     }
939
940     private class ARPRefreshHandler extends TimerTask {
941         @Override
942         @SuppressWarnings("deprecation")
943         public void run() {
944             if ((clusterContainerService != null) && !clusterContainerService.amICoordinator()) {
945                 return;
946             }
947             if ((switchManager != null) && !switchManager.isHostRefreshEnabled()) {
948                 /*
949                  * The host probe procedure was disabled by CLI
950                  */
951                 return;
952             }
953             if (hostsDB == null) {
954                 /* hostsDB is not allocated yet */
955                 logger.error("ARPRefreshHandler(): hostsDB is not allocated yet:");
956                 return;
957             }
958             for (Entry<InetAddress, HostNodeConnector> entry : hostsDB.entrySet()) {
959                 HostNodeConnector host = entry.getValue();
960                 if (host.isStaticHost()) {
961                     /* this host was learned via API3, don't age it out */
962                     continue;
963                 }
964
965                 short arp_cntdown = host.getArpSendCountDown();
966                 arp_cntdown--;
967                 if (arp_cntdown > switchManager.getHostRetryCount()) {
968                     host.setArpSendCountDown(arp_cntdown);
969                 } else if (arp_cntdown <= 0) {
970                     /*
971                      * No ARP Reply received in last 2 minutes, remove this host
972                      * and inform applications
973                      */
974                     removeKnownHost(entry.getKey());
975                     notifyHostLearnedOrRemoved(host, false);
976                 } else if (arp_cntdown <= switchManager.getHostRetryCount()) {
977                     /*
978                      * Use the services of arphandler to check if host is still
979                      * there
980                      */
981                     if (logger.isTraceEnabled()) {
982                         logger.trace(
983                                 "ARP Probing ({}) for {}({})",
984                                 new Object[] { arp_cntdown, host.getNetworkAddress().getHostAddress(),
985                                         HexEncode.bytesToHexString(host.getDataLayerAddressBytes()) });
986                     }
987                     host.setArpSendCountDown(arp_cntdown);
988                     hostFinder.probe(host);
989                 }
990             }
991         }
992     }
993
994     /**
995      * Inform the controller IP to MAC binding of a host and its connectivity to
996      * an openflow switch in terms of Node, port, and VLAN.
997      *
998      * @param networkAddr
999      *            IP address of the host
1000      * @param dataLayer
1001      *            Address MAC address of the host
1002      * @param nc
1003      *            NodeConnector to which host is connected
1004      * @param port
1005      *            Port of the switch to which host is connected
1006      * @param vlan
1007      *            Vlan of which this host is member of
1008      *
1009      * @return Status The status object as described in {@code Status}
1010      *         indicating the result of this action.
1011      */
1012
1013     public Status addStaticHostReq(InetAddress networkAddr, byte[] dataLayerAddress, NodeConnector nc, short vlan) {
1014         if (dataLayerAddress.length != NetUtils.MACAddrLengthInBytes) {
1015             return new Status(StatusCode.BADREQUEST, "Invalid MAC address");
1016         }
1017
1018         if (nc == null) {
1019             return new Status(StatusCode.BADREQUEST, "Invalid NodeConnector");
1020         }
1021         HostNodeConnector host = null;
1022         try {
1023             host = new HostNodeConnector(dataLayerAddress, networkAddr, nc, vlan);
1024             if (hostExists(host)) {
1025                 // This host is already learned either via ARP or through a
1026                 // northbound request
1027                 HostNodeConnector transHost = hostsDB.get(networkAddr);
1028                 transHost.setStaticHost(true);
1029                 return new Status(StatusCode.SUCCESS, null);
1030             }
1031
1032             if (hostsDB.get(networkAddr) != null) {
1033                 // There is already a host with this IP address (but behind
1034                 // a different (switch, port, vlan) tuple. Return an error
1035                 return new Status(StatusCode.CONFLICT, "Existing IP, Use PUT to update");
1036             }
1037             host.setStaticHost(true);
1038             /*
1039              * Check if the nc is an ISL port
1040              */
1041             if (topologyManager != null) {
1042                 if (topologyManager.isInternal(nc)) {
1043                     return new Status(StatusCode.BADREQUEST, "Cannot add host on ISL port");
1044                 }
1045             }
1046             /*
1047              * Before adding host, Check if the switch and the port have already
1048              * come up
1049              */
1050             if (switchManager.isNodeConnectorEnabled(nc)) {
1051                 learnNewHost(host);
1052                 notifyHostLearnedOrRemoved(host, true);
1053             } else {
1054                 inactiveStaticHosts.put(nc, host);
1055                 logger.debug("Switch or switchport is not up, adding host {} to inactive list",
1056                         networkAddr.getHostName());
1057             }
1058             return new Status(StatusCode.SUCCESS, null);
1059         } catch (ConstructionException e) {
1060             logger.error("", e);
1061             return new Status(StatusCode.INTERNALERROR, "Host could not be created");
1062         }
1063
1064     }
1065
1066     /**
1067      * Update the controller IP to MAC binding of a host and its connectivity to
1068      * an openflow switch in terms of switch id, switch port, and VLAN.
1069      *
1070      * @param networkAddr
1071      *            IP address of the host
1072      * @param dataLayer
1073      *            Address MAC address of the host
1074      * @param nc
1075      *            NodeConnector to which host is connected
1076      * @param port
1077      *            Port of the switch to which host is connected
1078      * @param vlan
1079      *            Vlan of which this host is member of
1080      *
1081      * @return Status The status object as described in {@code Status}
1082      *         indicating the result of this action.
1083      */
1084     public Status updateHostReq(InetAddress networkAddr, byte[] dataLayerAddress, NodeConnector nc, short vlan) {
1085         HostNodeConnector tobeUpdatedHost;
1086         HostNodeConnector host = null;
1087
1088         if (dataLayerAddress.length != NetUtils.MACAddrLengthInBytes) {
1089             return new Status(StatusCode.BADREQUEST, "Invalid MAC address");
1090         }
1091
1092         if (nc == null) {
1093             return new Status(StatusCode.BADREQUEST, "Invalid NodeConnector");
1094         }
1095
1096         try {
1097             host = new HostNodeConnector(dataLayerAddress, networkAddr, nc, vlan);
1098             if (hostExists(host)) {
1099                 return new Status(StatusCode.BADREQUEST, "Host already exists");
1100             }
1101
1102             if ((tobeUpdatedHost = hostsDB.get(networkAddr)) != null) {
1103                 if (hostsDB.replace(networkAddr, tobeUpdatedHost, host)) {
1104                     logger.debug("Host replaced from hostsDB. Old host: {} New Host: {}", tobeUpdatedHost, host);
1105                     notifyHostLearnedOrRemoved(tobeUpdatedHost, false);
1106                     notifyHostLearnedOrRemoved(host, true);
1107                     return new Status(StatusCode.SUCCESS);
1108                 } else {
1109                     logger.error("Static host replacement failed from hostsDB, Replaced Host: {}, New Host: {}",
1110                             tobeUpdatedHost, host);
1111                     return new Status(StatusCode.INTERNALERROR,
1112                             "Host Replacement Failed due to presence of another host with same IP");
1113                 }
1114             }
1115
1116             // Check if the host exists in inactive hosts database
1117             if ((tobeUpdatedHost = inactiveStaticHosts.get(nc)) != null) {
1118                 if (inactiveStaticHosts.replace(nc, tobeUpdatedHost, host)) {
1119                     logger.debug("Host replaced from inactive hostsDB. Old host: {} New Host: {}", tobeUpdatedHost,
1120                             host);
1121                     return new Status(StatusCode.SUCCESS);
1122                 } else {
1123                     logger.error("Static host replacement failed, Replaced Host: {}, New Host: {}", tobeUpdatedHost,
1124                             host);
1125                     return new Status(StatusCode.INTERNALERROR,
1126                             "Host Replacement Failed due to presence of another host with same IP");
1127                 }
1128             }
1129
1130             // Host doesn't exist
1131             return new Status(StatusCode.BADREQUEST, "Host doesn't exists, can't update");
1132         } catch (ConstructionException e) {
1133             logger.error("", e);
1134             return new Status(StatusCode.INTERNALERROR, "host object creation failure");
1135         }
1136     }
1137
1138     /**
1139      * Remove from the controller IP to MAC binding of a host and its
1140      * connectivity to an openflow switch
1141      *
1142      * @param networkAddr
1143      *            IP address of the host
1144      *
1145      * @return boolean true if the host was removed successfully, false
1146      *         otherwise
1147      */
1148
1149     public Status removeStaticHostReq(InetAddress networkAddress) {
1150         // Check if host is in active hosts database
1151         HostNodeConnector host = getHostFromOnActiveDB(networkAddress);
1152         if (host != null) {
1153             // Validation check
1154             if (!host.isStaticHost()) {
1155                 return new Status(StatusCode.FORBIDDEN, "Host " + networkAddress.getHostName() + " is not static");
1156             }
1157             // Remove and notify
1158             notifyHostLearnedOrRemoved(host, false);
1159             removeKnownHost(networkAddress);
1160             return new Status(StatusCode.SUCCESS, null);
1161         }
1162
1163         // Check if host is in inactive hosts database
1164         Entry<NodeConnector, HostNodeConnector> entry = getHostFromInactiveDB(networkAddress);
1165         if (entry != null) {
1166             host = entry.getValue();
1167             // Validation check
1168             if (!host.isStaticHost()) {
1169                 return new Status(StatusCode.FORBIDDEN, "Host " + networkAddress.getHostName() + " is not static");
1170             }
1171             this.removeHostFromInactiveDB(networkAddress);
1172             return new Status(StatusCode.SUCCESS, null);
1173         }
1174
1175         // Host is neither in active nor inactive hosts database
1176         return new Status(StatusCode.NOTFOUND, "Host does not exist");
1177     }
1178
1179     @Override
1180     public void modeChangeNotify(Node node, boolean proactive) {
1181         logger.debug("Set Switch {} Mode to {}", node.getID(), proactive);
1182     }
1183
1184     @Override
1185     public void notifyNode(Node node, UpdateType type, Map<String, Property> propMap) {
1186         if (node == null)
1187             return;
1188
1189         switch (type) {
1190         case REMOVED:
1191             logger.debug("Received removed node {}", node);
1192             for (Entry<InetAddress, HostNodeConnector> entry : hostsDB.entrySet()) {
1193                 HostNodeConnector host = entry.getValue();
1194                 if (host.getnodeconnectorNode().equals(node)) {
1195                     logger.debug("Node: {} is down, remove from Hosts_DB", node);
1196                     removeKnownHost(entry.getKey());
1197                     notifyHostLearnedOrRemoved(host, false);
1198                 }
1199             }
1200             break;
1201         default:
1202             break;
1203         }
1204     }
1205
1206     @Override
1207     public void notifyNodeConnector(NodeConnector nodeConnector, UpdateType type, Map<String, Property> propMap) {
1208         if (nodeConnector == null)
1209             return;
1210
1211         boolean up = false;
1212         switch (type) {
1213         case ADDED:
1214             up = true;
1215             break;
1216         case REMOVED:
1217             break;
1218         case CHANGED:
1219             State state = (State) propMap.get(State.StatePropName);
1220             if ((state != null) && (state.getValue() == State.EDGE_UP)) {
1221                 up = true;
1222             }
1223             break;
1224         default:
1225             return;
1226         }
1227
1228         if (up) {
1229             handleNodeConnectorStatusUp(nodeConnector);
1230         } else {
1231             handleNodeConnectorStatusDown(nodeConnector);
1232         }
1233     }
1234
1235     @Override
1236     public Status addStaticHost(String networkAddress, String dataLayerAddress, NodeConnector nc, String vlan) {
1237         try {
1238             InetAddress ip = InetAddress.getByName(networkAddress);
1239             if (nc == null) {
1240                 return new Status(StatusCode.BADREQUEST, "Invalid NodeId");
1241             }
1242             return addStaticHostReq(ip, HexEncode.bytesFromHexString(dataLayerAddress), nc, Short.valueOf(vlan));
1243         } catch (UnknownHostException e) {
1244             logger.error("", e);
1245             return new Status(StatusCode.BADREQUEST, "Invalid Address");
1246         }
1247     }
1248
1249     @Override
1250     public Status removeStaticHost(String networkAddress) {
1251         InetAddress address;
1252         try {
1253             address = InetAddress.getByName(networkAddress);
1254             return removeStaticHostReq(address);
1255         } catch (UnknownHostException e) {
1256             logger.error("", e);
1257             return new Status(StatusCode.BADREQUEST, "Invalid Address");
1258         }
1259     }
1260
1261     private void handleNodeConnectorStatusUp(NodeConnector nodeConnector) {
1262         ARPPending arphost;
1263
1264         logger.debug("handleNodeConnectorStatusUp {}", nodeConnector);
1265
1266         for (int i = 0; i < failedARPReqList.size(); i++) {
1267             arphost = failedARPReqList.get(i);
1268             logger.debug("Sending the ARP from FailedARPReqList fors IP: {}", arphost.getHostIP().getHostAddress());
1269             hostFinder.find(arphost.getHostIP());
1270         }
1271         HostNodeConnector host = inactiveStaticHosts.get(nodeConnector);
1272         if (host != null) {
1273             inactiveStaticHosts.remove(nodeConnector);
1274             learnNewHost(host);
1275             notifyHostLearnedOrRemoved(host, true);
1276         }
1277     }
1278
1279     private void handleNodeConnectorStatusDown(NodeConnector nodeConnector) {
1280         logger.debug("handleNodeConnectorStatusDown {}", nodeConnector);
1281
1282         for (Entry<InetAddress, HostNodeConnector> entry : hostsDB.entrySet()) {
1283             HostNodeConnector host = entry.getValue();
1284             if (host.getnodeConnector().equals(nodeConnector)) {
1285                 logger.debug(" NodeConnector: {} is down, remove from Hosts_DB", nodeConnector);
1286                 removeKnownHost(entry.getKey());
1287                 notifyHostLearnedOrRemoved(host, false);
1288             }
1289         }
1290     }
1291
1292     void setClusterContainerService(IClusterContainerServices s) {
1293         logger.debug("Cluster Service set");
1294         this.clusterContainerService = s;
1295     }
1296
1297     void unsetClusterContainerService(IClusterContainerServices s) {
1298         if (this.clusterContainerService == s) {
1299             logger.debug("Cluster Service removed!");
1300             this.clusterContainerService = null;
1301         }
1302     }
1303
1304     void setSwitchManager(ISwitchManager s) {
1305         logger.debug("SwitchManager set");
1306         this.switchManager = s;
1307     }
1308
1309     void unsetSwitchManager(ISwitchManager s) {
1310         if (this.switchManager == s) {
1311             logger.debug("SwitchManager removed!");
1312             this.switchManager = null;
1313         }
1314     }
1315
1316     public String getContainerName() {
1317         if (containerName == null)
1318             return GlobalConstants.DEFAULT.toString();
1319         return containerName;
1320     }
1321
1322     /**
1323      * Function called by the dependency manager when all the required
1324      * dependencies are satisfied
1325      *
1326      */
1327     void init(Component c) {
1328         Dictionary<?, ?> props = c.getServiceProperties();
1329         if (props != null) {
1330             this.containerName = (String) props.get("containerName");
1331             logger.debug("Running containerName: {}", this.containerName);
1332         } else {
1333             // In the Global instance case the containerName is empty
1334             this.containerName = "";
1335         }
1336         startUp();
1337     }
1338
1339     /**
1340      * Function called by the dependency manager when at least one dependency
1341      * become unsatisfied or when the component is shutting down because for
1342      * example bundle is being stopped.
1343      *
1344      */
1345     void destroy() {
1346         destroyCache();
1347     }
1348
1349     /**
1350      * Function called by dependency manager after "init ()" is called and after
1351      * the services provided by the class are registered in the service registry
1352      *
1353      */
1354     void start() {
1355     }
1356
1357     /**
1358      * Function called by the dependency manager before the services exported by
1359      * the component are unregistered, this will be followed by a "destroy ()"
1360      * calls
1361      *
1362      */
1363     void stop() {
1364     }
1365
1366     @Override
1367     public void edgeOverUtilized(Edge edge) {
1368         // TODO Auto-generated method stub
1369
1370     }
1371
1372     @Override
1373     public void edgeUtilBackToNormal(Edge edge) {
1374         // TODO Auto-generated method stub
1375
1376     }
1377
1378 }