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