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