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