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