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