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